drizzle-cube 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/express/index.cjs +1 -1
  3. package/dist/adapters/express/index.js +4 -4
  4. package/dist/adapters/fastify/index.cjs +1 -1
  5. package/dist/adapters/fastify/index.js +4 -4
  6. package/dist/adapters/{handler-3LGcjLtr.js → handler-BC3nFNxV.js} +2 -2
  7. package/dist/adapters/{handler-BzzbVpcl.cjs → handler-Cqf-CqAS.cjs} +2 -2
  8. package/dist/adapters/hono/index.cjs +1 -1
  9. package/dist/adapters/hono/index.js +4 -4
  10. package/dist/adapters/locale-BoiA6WiV.cjs +198 -0
  11. package/dist/adapters/{locale-DTnJrxm1.js → locale-D9VQkLXt.js} +442 -404
  12. package/dist/adapters/mcp-tools.cjs +1 -1
  13. package/dist/adapters/mcp-tools.js +2 -2
  14. package/dist/adapters/mcp-transport-B0mgxRnJ.js +579 -0
  15. package/dist/adapters/mcp-transport-irsahKmD.cjs +39 -0
  16. package/dist/adapters/nextjs/index.cjs +1 -1
  17. package/dist/adapters/nextjs/index.js +4 -4
  18. package/dist/adapters/{openai-C4BD8xnN.cjs → openai-B4N3KfTG.cjs} +1 -1
  19. package/dist/adapters/{openai-CaSQEduB.js → openai-BWdm0JvG.js} +1 -1
  20. package/dist/adapters/openai-CoqT_FM5.cjs +16 -0
  21. package/dist/{server/openai-CqZg6zYL.js → adapters/openai-D0Nsvc9L.js} +824 -720
  22. package/dist/adapters/{utils-DOg9oGdt.js → utils-CTYvfZ3I.js} +711 -713
  23. package/dist/adapters/{utils-DNrj-ryp.cjs → utils-XPOzzMdY.cjs} +5 -5
  24. package/dist/adapters/utils.cjs +1 -1
  25. package/dist/adapters/utils.js +1 -1
  26. package/dist/cli/index.cjs +2 -2
  27. package/dist/client/charts.js +10 -10
  28. package/dist/client/chunks/{DashboardEditModal-cSSIAZGy.js → DashboardEditModal-IU_0dgfC.js} +12 -12
  29. package/dist/client/chunks/{DashboardEditModal-cSSIAZGy.js.map → DashboardEditModal-IU_0dgfC.js.map} +1 -1
  30. package/dist/client/chunks/{FieldSearchModal-CZNo4pNK.js → FieldSearchModal-BCWanpPX.js} +3 -3
  31. package/dist/client/chunks/{FieldSearchModal-CZNo4pNK.js.map → FieldSearchModal-BCWanpPX.js.map} +1 -1
  32. package/dist/client/chunks/KpiDelta-_igN6cJa.js +2 -0
  33. package/dist/client/chunks/KpiNumber-t5n8PtRU.js +2 -0
  34. package/dist/client/chunks/KpiText-BCZJJ6a0.js +2 -0
  35. package/dist/client/chunks/{RetentionCombinedChart-BD8tGeM_.js → RetentionCombinedChart-CQMBODsK.js} +2 -2
  36. package/dist/client/chunks/{RetentionCombinedChart-BD8tGeM_.js.map → RetentionCombinedChart-CQMBODsK.js.map} +1 -1
  37. package/dist/client/chunks/SchemaVisualization-BUUhlOvG.js +2 -0
  38. package/dist/client/chunks/SchemaVisualizationLazy-CwaPCUL0.js +2 -0
  39. package/dist/client/chunks/{analysis-builder-BeVZhiQ5.js → analysis-builder-Dm6eD_AX.js} +6 -6
  40. package/dist/client/chunks/{analysis-builder-BeVZhiQ5.js.map → analysis-builder-Dm6eD_AX.js.map} +1 -1
  41. package/dist/client/chunks/{analysis-builder-shared-BWc7ZZnG.js → analysis-builder-shared-DT5bXwCA.js} +6 -6
  42. package/dist/client/chunks/{analysis-builder-shared-BWc7ZZnG.js.map → analysis-builder-shared-DT5bXwCA.js.map} +1 -1
  43. package/dist/client/chunks/{chart-area-D63kG8OT.js → chart-area-DDti9Qtp.js} +2 -2
  44. package/dist/client/chunks/{chart-area-D63kG8OT.js.map → chart-area-DDti9Qtp.js.map} +1 -1
  45. package/dist/client/chunks/{chart-bar-BEfsCLjl.js → chart-bar-B3s9qDlh.js} +2 -2
  46. package/dist/client/chunks/{chart-bar-BEfsCLjl.js.map → chart-bar-B3s9qDlh.js.map} +1 -1
  47. package/dist/client/chunks/{chart-data-table-C3Xh9jwL.js → chart-data-table-Qrt6EAno.js} +17 -17
  48. package/dist/client/chunks/{chart-data-table-C3Xh9jwL.js.map → chart-data-table-Qrt6EAno.js.map} +1 -1
  49. package/dist/client/chunks/{chart-kpi-delta-CYE0S1x_.js → chart-kpi-delta-CgldZ7zO.js} +3 -3
  50. package/dist/client/chunks/{chart-kpi-delta-CYE0S1x_.js.map → chart-kpi-delta-CgldZ7zO.js.map} +1 -1
  51. package/dist/client/chunks/{chart-kpi-number-BlZ79xHW.js → chart-kpi-number-ByfuX1ki.js} +5 -5
  52. package/dist/client/chunks/{chart-kpi-number-BlZ79xHW.js.map → chart-kpi-number-ByfuX1ki.js.map} +1 -1
  53. package/dist/client/chunks/{chart-kpi-text-DY1BnxPe.js → chart-kpi-text-DeNuDraJ.js} +2 -2
  54. package/dist/client/chunks/{chart-kpi-text-DY1BnxPe.js.map → chart-kpi-text-DeNuDraJ.js.map} +1 -1
  55. package/dist/client/chunks/{chart-line-CBsTThTv.js → chart-line-RdZwtk27.js} +2 -2
  56. package/dist/client/chunks/{chart-line-CBsTThTv.js.map → chart-line-RdZwtk27.js.map} +1 -1
  57. package/dist/client/chunks/{chart-markdown-BWaWVkuz.js → chart-markdown-CiGRZdJj.js} +1203 -1139
  58. package/dist/client/chunks/chart-markdown-CiGRZdJj.js.map +1 -0
  59. package/dist/client/chunks/{chart-measure-profile-B41qCTBG.js → chart-measure-profile-Ckjw9bX6.js} +2 -2
  60. package/dist/client/chunks/{chart-measure-profile-B41qCTBG.js.map → chart-measure-profile-Ckjw9bX6.js.map} +1 -1
  61. package/dist/client/chunks/{chart-pie-Djbu8x2v.js → chart-pie-BvY4FY__.js} +2 -2
  62. package/dist/client/chunks/{chart-pie-Djbu8x2v.js.map → chart-pie-BvY4FY__.js.map} +1 -1
  63. package/dist/client/chunks/{chart-radar-BsTcKV0K.js → chart-radar-DjiiEAmc.js} +2 -2
  64. package/dist/client/chunks/{chart-radar-BsTcKV0K.js.map → chart-radar-DjiiEAmc.js.map} +1 -1
  65. package/dist/client/chunks/{chart-radial-bar-Du7XNnwE.js → chart-radial-bar-lla_JEYu.js} +2 -2
  66. package/dist/client/chunks/{chart-radial-bar-Du7XNnwE.js.map → chart-radial-bar-lla_JEYu.js.map} +1 -1
  67. package/dist/client/chunks/{chart-scatter-D8krEYsA.js → chart-scatter-DwXnI0rr.js} +2 -2
  68. package/dist/client/chunks/{chart-scatter-D8krEYsA.js.map → chart-scatter-DwXnI0rr.js.map} +1 -1
  69. package/dist/client/chunks/{chart-tree-map-C5C2iaWM.js → chart-tree-map-DJHoA26f.js} +2 -2
  70. package/dist/client/chunks/{chart-tree-map-C5C2iaWM.js.map → chart-tree-map-DJHoA26f.js.map} +1 -1
  71. package/dist/client/chunks/{chart-waterfall-BGdPrJ5Y.js → chart-waterfall-Y7c8csO5.js} +2 -2
  72. package/dist/client/chunks/{chart-waterfall-BGdPrJ5Y.js.map → chart-waterfall-Y7c8csO5.js.map} +1 -1
  73. package/dist/client/chunks/{core-DcfMGTVa.js → core-Dk6z6kC0.js} +2 -2
  74. package/dist/client/chunks/{core-DcfMGTVa.js.map → core-Dk6z6kC0.js.map} +1 -1
  75. package/dist/client/chunks/{exceljs.min-CcjgM-qg.js → exceljs.min-DaJsLlWM.js} +24 -24
  76. package/dist/client/chunks/{exceljs.min-CcjgM-qg.js.map → exceljs.min-DaJsLlWM.js.map} +1 -1
  77. package/dist/client/chunks/{schema-visualization-Xp60Ff2W.js → schema-visualization-DWwJukK7.js} +8 -8
  78. package/dist/client/chunks/{schema-visualization-Xp60Ff2W.js.map → schema-visualization-DWwJukK7.js.map} +1 -1
  79. package/dist/client/chunks/{syntaxHighlighting-CnDujqwg.js → syntaxHighlighting-D8J6Yt9j.js} +2 -2
  80. package/dist/client/chunks/{syntaxHighlighting-CnDujqwg.js.map → syntaxHighlighting-D8J6Yt9j.js.map} +1 -1
  81. package/dist/client/chunks/{useDebounce-CfmUMFau.js → useDebounce-DyJVREop.js} +2 -2
  82. package/dist/client/chunks/{useDebounce-CfmUMFau.js.map → useDebounce-DyJVREop.js.map} +1 -1
  83. package/dist/client/chunks/{useExplainAI-BKGmejIj.js → useExplainAI-CxSkjocM.js} +4 -4
  84. package/dist/client/chunks/{useExplainAI-BKGmejIj.js.map → useExplainAI-CxSkjocM.js.map} +1 -1
  85. package/dist/client/chunks/{utils-BldkcRHv.js → utils-BHZdKxua.js} +2 -2
  86. package/dist/client/chunks/{utils-BldkcRHv.js.map → utils-BHZdKxua.js.map} +1 -1
  87. package/dist/client/chunks/{vendor-ClXpIiea.js → vendor-CBD_Olr0.js} +8 -8
  88. package/dist/client/chunks/{vendor-ClXpIiea.js.map → vendor-CBD_Olr0.js.map} +1 -1
  89. package/dist/client/components.js +3 -3
  90. package/dist/client/hooks.js +3 -3
  91. package/dist/client/icons.js +1 -1
  92. package/dist/client/index.js +11 -11
  93. package/dist/client/providers.js +1 -1
  94. package/dist/client/schema.js +1 -1
  95. package/dist/client/utils.js +5 -5
  96. package/dist/client-bundle-stats.html +1 -1
  97. package/dist/mcp-app/mcp-app.html +21 -21
  98. package/dist/server/index.cjs +42 -42
  99. package/dist/server/index.js +1009 -971
  100. package/dist/server/{openai-D9Zjuby1.cjs → openai-BfiZU0rG.cjs} +1 -1
  101. package/dist/server/openai-BwsBio1K.cjs +16 -0
  102. package/dist/server/{openai-rwauPzCT.js → openai-CLWSwD-D.js} +1 -1
  103. package/dist/{adapters/openai-BAnEZgKZ.js → server/openai-zpXlGbbF.js} +824 -720
  104. package/package.json +2 -2
  105. package/dist/adapters/locale-DueXjqMh.cjs +0 -198
  106. package/dist/adapters/mcp-transport-C7VLf4T5.js +0 -579
  107. package/dist/adapters/mcp-transport-poPHl_2j.cjs +0 -39
  108. package/dist/adapters/openai-4JP2B6pB.cjs +0 -16
  109. package/dist/client/chunks/KpiDelta-Dll_eCV1.js +0 -2
  110. package/dist/client/chunks/KpiNumber-BPlR92hI.js +0 -2
  111. package/dist/client/chunks/KpiText-BIxq7Jso.js +0 -2
  112. package/dist/client/chunks/SchemaVisualization-CCICjhvv.js +0 -2
  113. package/dist/client/chunks/SchemaVisualizationLazy-DraGsMx6.js +0 -2
  114. package/dist/client/chunks/chart-markdown-BWaWVkuz.js.map +0 -1
  115. package/dist/server/openai-DmuEbFd6.cjs +0 -16
@@ -1 +1 @@
1
- {"version":3,"file":"chart-pie-Djbu8x2v.js","names":[],"sources":["../../../src/client/components/charts/PieChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { PieChart as RechartsPieChart, Pie, Cell, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst PieChart = React.memo(function PieChart({\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 [hoveredLegend, setHoveredLegend] = useState<string | 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 showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat,\n innerRadius: displayConfig?.innerRadius || '0%'\n }\n\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.pie')}</div>\n </div>\n </div>\n )\n }\n\n let pieData: Array<{name: string, value: number}>\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: string\n let yAxisFields: string[]\n let seriesFields: string[] = []\n \n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format\n xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis\n yAxisFields = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis]\n seriesFields = chartConfig.series || []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format\n xAxisField = chartConfig.x\n yAxisFields = Array.isArray(chartConfig.y) ? chartConfig.y : [chartConfig.y]\n } else {\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\">{t('chart.runtime.configErrorHint.pieAxis')}</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || !yAxisFields || yAxisFields.length === 0) {\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\">{t('chart.runtime.configErrorHint.axisFields')}</div>\n </div>\n </div>\n )\n }\n\n if (seriesFields.length > 0) {\n // Use series-based transformation for dimension-based pie slices\n const { data: chartData } = transformChartDataWithSeries(\n data,\n xAxisField,\n yAxisFields,\n queryObject,\n seriesFields,\n getFieldLabel\n )\n \n // Convert series data to pie format\n pieData = []\n if (chartData.length > 0) {\n const firstRow = chartData[0]\n Object.keys(firstRow).forEach(key => {\n if (key !== 'name' && typeof firstRow[key] === 'number') {\n pieData.push({\n name: String(key),\n value: firstRow[key]\n })\n }\n })\n }\n } else {\n // Standard measure-based pie chart\n const granularity = getFieldGranularity(queryObject, xAxisField)\n pieData = data.map(item => {\n let name = formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown'\n // Handle boolean values with better labels\n if (typeof item[xAxisField] === 'boolean') {\n name = item[xAxisField] ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n }\n return {\n name,\n value: typeof item[yAxisFields[0]] === 'string' \n ? parseFloat(item[yAxisFields[0]]) \n : (item[yAxisFields[0]] || 0)\n }\n })\n }\n\n // Filter out invalid values (null, undefined, NaN, or zero)\n const originalLength = pieData.length\n pieData = pieData.filter(item => \n item.value != null && \n !isNaN(item.value) && \n item.value !== 0 && \n item.value > 0\n )\n \n if (pieData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n {originalLength > 0\n ? `Filtered out ${originalLength} data points (zero or invalid values)`\n : 'No data points to display in pie chart'\n }\n </div>\n </div>\n </div>\n )\n }\n \n return (\n <ChartContainer height={height}>\n <RechartsPieChart accessibilityLayer={false}>\n <Pie\n data={pieData}\n cx=\"50%\"\n cy=\"50%\"\n innerRadius={safeDisplayConfig.innerRadius !== '0%' ? safeDisplayConfig.innerRadius : undefined}\n outerRadius=\"70%\"\n dataKey=\"value\"\n label={!safeDisplayConfig.showLegend ? ({ name, percent }) =>\n `${name} ${((percent || 0) * 100).toFixed(0)}%`\n : undefined}\n cursor={drillEnabled ? 'pointer' : undefined}\n onClick={(sliceData: any, _index: number, event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled && sliceData) {\n onDataPointClick({\n dataPoint: sliceData,\n clickedField: yAxisFields[0],\n xValue: sliceData.name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }}\n >\n {pieData.map((_entry, index) => (\n <Cell\n key={`cell-${index}`}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === pieData[index].name ? 1 : 0.3) : 1}\n />\n ))}\n </Pie>\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 {safeDisplayConfig.showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.value || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n </RechartsPieChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'PieChart rendering 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: 'Pie 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 PieChart"],"mappings":"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"}
1
+ {"version":3,"file":"chart-pie-BvY4FY__.js","names":[],"sources":["../../../src/client/components/charts/PieChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { PieChart as RechartsPieChart, Pie, Cell, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst PieChart = React.memo(function PieChart({\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 [hoveredLegend, setHoveredLegend] = useState<string | 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 showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat,\n innerRadius: displayConfig?.innerRadius || '0%'\n }\n\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.pie')}</div>\n </div>\n </div>\n )\n }\n\n let pieData: Array<{name: string, value: number}>\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: string\n let yAxisFields: string[]\n let seriesFields: string[] = []\n \n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format\n xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis\n yAxisFields = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis]\n seriesFields = chartConfig.series || []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format\n xAxisField = chartConfig.x\n yAxisFields = Array.isArray(chartConfig.y) ? chartConfig.y : [chartConfig.y]\n } else {\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\">{t('chart.runtime.configErrorHint.pieAxis')}</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || !yAxisFields || yAxisFields.length === 0) {\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\">{t('chart.runtime.configErrorHint.axisFields')}</div>\n </div>\n </div>\n )\n }\n\n if (seriesFields.length > 0) {\n // Use series-based transformation for dimension-based pie slices\n const { data: chartData } = transformChartDataWithSeries(\n data,\n xAxisField,\n yAxisFields,\n queryObject,\n seriesFields,\n getFieldLabel\n )\n \n // Convert series data to pie format\n pieData = []\n if (chartData.length > 0) {\n const firstRow = chartData[0]\n Object.keys(firstRow).forEach(key => {\n if (key !== 'name' && typeof firstRow[key] === 'number') {\n pieData.push({\n name: String(key),\n value: firstRow[key]\n })\n }\n })\n }\n } else {\n // Standard measure-based pie chart\n const granularity = getFieldGranularity(queryObject, xAxisField)\n pieData = data.map(item => {\n let name = formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown'\n // Handle boolean values with better labels\n if (typeof item[xAxisField] === 'boolean') {\n name = item[xAxisField] ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n }\n return {\n name,\n value: typeof item[yAxisFields[0]] === 'string' \n ? parseFloat(item[yAxisFields[0]]) \n : (item[yAxisFields[0]] || 0)\n }\n })\n }\n\n // Filter out invalid values (null, undefined, NaN, or zero)\n const originalLength = pieData.length\n pieData = pieData.filter(item => \n item.value != null && \n !isNaN(item.value) && \n item.value !== 0 && \n item.value > 0\n )\n \n if (pieData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n {originalLength > 0\n ? `Filtered out ${originalLength} data points (zero or invalid values)`\n : 'No data points to display in pie chart'\n }\n </div>\n </div>\n </div>\n )\n }\n \n return (\n <ChartContainer height={height}>\n <RechartsPieChart accessibilityLayer={false}>\n <Pie\n data={pieData}\n cx=\"50%\"\n cy=\"50%\"\n innerRadius={safeDisplayConfig.innerRadius !== '0%' ? safeDisplayConfig.innerRadius : undefined}\n outerRadius=\"70%\"\n dataKey=\"value\"\n label={!safeDisplayConfig.showLegend ? ({ name, percent }) =>\n `${name} ${((percent || 0) * 100).toFixed(0)}%`\n : undefined}\n cursor={drillEnabled ? 'pointer' : undefined}\n onClick={(sliceData: any, _index: number, event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled && sliceData) {\n onDataPointClick({\n dataPoint: sliceData,\n clickedField: yAxisFields[0],\n xValue: sliceData.name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }}\n >\n {pieData.map((_entry, index) => (\n <Cell\n key={`cell-${index}`}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === pieData[index].name ? 1 : 0.3) : 1}\n />\n ))}\n </Pie>\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 {safeDisplayConfig.showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.value || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n </RechartsPieChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'PieChart rendering 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: 'Pie 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 PieChart"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CCl2IeXn.js";
2
2
  import { D as t, S as n, k as r, n as i, x as a, y as o } from "./chart-activity-grid-CWT0gLv4.js";
3
- import { c as s, l as c } from "./chart-area-D63kG8OT.js";
3
+ import { c as s, l as c } from "./chart-area-DDti9Qtp.js";
4
4
  import l, { useState as u } from "react";
5
5
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
6
6
  import { Legend as p, PolarAngleAxis as m, PolarGrid as h, PolarRadiusAxis as g, Radar as _, RadarChart as v } from "recharts";
@@ -151,4 +151,4 @@ var y = /* @__PURE__ */ e({ default: () => b }), b = l.memo(function({ data: e,
151
151
  //#endregion
152
152
  export { y as n, b as t };
153
153
 
154
- //# sourceMappingURL=chart-radar-BsTcKV0K.js.map
154
+ //# sourceMappingURL=chart-radar-DjiiEAmc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-radar-BsTcKV0K.js","names":[],"sources":["../../../src/client/components/charts/RadarChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { RadarChart as RechartsRadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps } from '../../types'\n\nconst RadarChart = React.memo(function RadarChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n \n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\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.radar')}</div>\n </div>\n </div>\n )\n }\n\n let radarData: any[]\n let seriesKeys: string[] = []\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Subject/category field\n const yAxisFields = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis] // Value fields\n const seriesFields = chartConfig.series || []\n\n // Use shared function to transform data and handle series\n const { data: chartData, seriesKeys: transformedSeriesKeys } = transformChartDataWithSeries(\n data, \n xAxisField, \n yAxisFields, \n queryObject,\n seriesFields\n )\n \n radarData = chartData\n seriesKeys = transformedSeriesKeys\n } else {\n // Legacy format or auto-detection - try to find suitable fields\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find subject/category field\n const subjectField = keys.find(key => \n typeof firstRow[key] === 'string' ||\n key.toLowerCase().includes('subject') ||\n key.toLowerCase().includes('name') ||\n key.toLowerCase().includes('category')\n ) || keys[0]\n\n // Find numeric fields for values\n const valueFields = keys.filter(key => \n typeof firstRow[key] === 'number' && key !== subjectField\n )\n\n if (valueFields.length === 0) {\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\">{t('chart.runtime.configErrorHint.radarNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for radar chart\n if (subjectField) {\n // Use subject field for radar categories\n const granularity = getFieldGranularity(queryObject, subjectField)\n radarData = data.map(item => {\n const transformedItem: any = {\n name: formatTimeValue(item[subjectField], granularity) || String(item[subjectField]) || 'Unknown'\n }\n \n valueFields.forEach(field => {\n const displayName = field.split('.').pop() || field\n transformedItem[displayName] = typeof item[field] === 'string' \n ? parseFloat(item[field]) \n : (item[field] || 0)\n })\n \n return transformedItem\n })\n \n seriesKeys = valueFields.map(field => field.split('.').pop() || field)\n } else {\n // Fallback - use first value field only\n radarData = data.map(item => ({\n name: String(item[keys[0]] || 'Unknown'),\n value: typeof item[valueFields[0]] === 'string' \n ? parseFloat(item[valueFields[0]]) \n : (item[valueFields[0]] || 0)\n }))\n seriesKeys = ['value']\n }\n }\n \n // Validate transformed data\n if (!radarData || radarData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for radar chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsRadarChart data={radarData} margin={{ top: 20, right: 80, bottom: 20, left: 80 }} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <PolarGrid />\n )}\n <PolarAngleAxis\n dataKey=\"name\"\n tick={{ fontSize: 12 }}\n className=\"text-dc-text-muted\"\n />\n <PolarRadiusAxis\n tick={{ fontSize: 10 }}\n className=\"text-dc-text-muted\"\n tickFormatter={safeDisplayConfig.leftYAxisFormat\n ? (value: any) => formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : undefined\n }\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 {(safeDisplayConfig.showLegend && seriesKeys.length > 1) && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"rect\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {seriesKeys.map((seriesKey, index) => (\n <Radar\n key={seriesKey}\n name={seriesKey}\n dataKey={seriesKey}\n stroke={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 0.6 : 0.1) : 0.3}\n strokeOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n strokeWidth={2}\n />\n ))}\n </RechartsRadarChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'RadarChart rendering 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: 'Radar 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 RadarChart"],"mappings":"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"}
1
+ {"version":3,"file":"chart-radar-DjiiEAmc.js","names":[],"sources":["../../../src/client/components/charts/RadarChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { RadarChart as RechartsRadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps } from '../../types'\n\nconst RadarChart = React.memo(function RadarChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n \n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\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.radar')}</div>\n </div>\n </div>\n )\n }\n\n let radarData: any[]\n let seriesKeys: string[] = []\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Subject/category field\n const yAxisFields = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis] // Value fields\n const seriesFields = chartConfig.series || []\n\n // Use shared function to transform data and handle series\n const { data: chartData, seriesKeys: transformedSeriesKeys } = transformChartDataWithSeries(\n data, \n xAxisField, \n yAxisFields, \n queryObject,\n seriesFields\n )\n \n radarData = chartData\n seriesKeys = transformedSeriesKeys\n } else {\n // Legacy format or auto-detection - try to find suitable fields\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find subject/category field\n const subjectField = keys.find(key => \n typeof firstRow[key] === 'string' ||\n key.toLowerCase().includes('subject') ||\n key.toLowerCase().includes('name') ||\n key.toLowerCase().includes('category')\n ) || keys[0]\n\n // Find numeric fields for values\n const valueFields = keys.filter(key => \n typeof firstRow[key] === 'number' && key !== subjectField\n )\n\n if (valueFields.length === 0) {\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\">{t('chart.runtime.configErrorHint.radarNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for radar chart\n if (subjectField) {\n // Use subject field for radar categories\n const granularity = getFieldGranularity(queryObject, subjectField)\n radarData = data.map(item => {\n const transformedItem: any = {\n name: formatTimeValue(item[subjectField], granularity) || String(item[subjectField]) || 'Unknown'\n }\n \n valueFields.forEach(field => {\n const displayName = field.split('.').pop() || field\n transformedItem[displayName] = typeof item[field] === 'string' \n ? parseFloat(item[field]) \n : (item[field] || 0)\n })\n \n return transformedItem\n })\n \n seriesKeys = valueFields.map(field => field.split('.').pop() || field)\n } else {\n // Fallback - use first value field only\n radarData = data.map(item => ({\n name: String(item[keys[0]] || 'Unknown'),\n value: typeof item[valueFields[0]] === 'string' \n ? parseFloat(item[valueFields[0]]) \n : (item[valueFields[0]] || 0)\n }))\n seriesKeys = ['value']\n }\n }\n \n // Validate transformed data\n if (!radarData || radarData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for radar chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsRadarChart data={radarData} margin={{ top: 20, right: 80, bottom: 20, left: 80 }} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <PolarGrid />\n )}\n <PolarAngleAxis\n dataKey=\"name\"\n tick={{ fontSize: 12 }}\n className=\"text-dc-text-muted\"\n />\n <PolarRadiusAxis\n tick={{ fontSize: 10 }}\n className=\"text-dc-text-muted\"\n tickFormatter={safeDisplayConfig.leftYAxisFormat\n ? (value: any) => formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : undefined\n }\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 {(safeDisplayConfig.showLegend && seriesKeys.length > 1) && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"rect\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {seriesKeys.map((seriesKey, index) => (\n <Radar\n key={seriesKey}\n name={seriesKey}\n dataKey={seriesKey}\n stroke={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 0.6 : 0.1) : 0.3}\n strokeOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n strokeWidth={2}\n />\n ))}\n </RechartsRadarChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'RadarChart rendering 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: 'Radar 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 RadarChart"],"mappings":";;;;;;;iDASM,IAAa,EAAM,KAAK,SAAoB,EAChD,SACA,gBACA,mBAAgB,EAAE,EAClB,gBACA,YAAS,QACT,mBACa;CACb,IAAM,EAAE,SAAM,GAAgB,EACxB,CAAC,GAAe,KAAoB,EAAwB,KAAK;AAEvE,KAAI;EACF,IAAM,IAAoB;GACxB,YAAY,GAAe,cAAc;GACzC,aAAa,GAAe,eAAe;GAC3C,UAAU,GAAe,YAAY;GACrC,iBAAiB,GAAe;GACjC;AAED,MAAI,CAAC,KAAQ,EAAK,WAAW,EAC3B,QACE,kBAAC,OAAD;GAAK,WAAU;GAAyE,OAAO,EAAE,WAAQ;aACvG,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAuC,EAAE,uBAAuB;KAAO,CAAA,EACtF,kBAAC,OAAD;KAAK,WAAU;eAAqC,EAAE,iCAAiC;KAAO,CAAA,CAC1F;;GACF,CAAA;EAIV,IAAI,GACA,IAAuB,EAAE;AAE7B,MAAI,GAAa,SAAS,GAAa,OAAO;GAO5C,IAAM,EAAE,MAAM,GAAW,YAAY,MAA0B,EAC7D,GANiB,MAAM,QAAQ,EAAY,MAAM,GAAG,EAAY,MAAM,KAAK,EAAY,OACrE,MAAM,QAAQ,EAAY,MAAM,GAAG,EAAY,QAAQ,CAAC,EAAY,MAAM,EAQ5F,GAPmB,EAAY,UAAU,EAAE,CAS5C;AAGD,GADA,IAAY,GACZ,IAAa;SACR;GAEL,IAAM,IAAW,EAAK,IAChB,IAAO,OAAO,KAAK,EAAS,EAG5B,IAAe,EAAK,MAAK,MAC7B,OAAO,EAAS,MAAS,YACzB,EAAI,aAAa,CAAC,SAAS,UAAU,IACrC,EAAI,aAAa,CAAC,SAAS,OAAO,IAClC,EAAI,aAAa,CAAC,SAAS,WAAW,CACvC,IAAI,EAAK,IAGJ,IAAc,EAAK,QAAO,MAC9B,OAAO,EAAS,MAAS,YAAY,MAAQ,EAC9C;AAED,OAAI,EAAY,WAAW,EACzB,QACE,kBAAC,OAAD;IAAK,WAAU;IAAsE,OAAO,EAAE,WAAQ;cACpG,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAuC,EAAE,4BAA4B;MAAO,CAAA,EAC3F,kBAAC,OAAD;MAAK,WAAU;gBAAc,EAAE,6CAA6C;MAAO,CAAA,CAC/E;;IACF,CAAA;AAKV,OAAI,GAAc;IAEhB,IAAM,IAAc,EAAoB,GAAa,EAAa;AAgBlE,IAfA,IAAY,EAAK,KAAI,MAAQ;KAC3B,IAAM,IAAuB,EAC3B,MAAM,EAAgB,EAAK,IAAe,EAAY,IAAI,OAAO,EAAK,GAAc,IAAI,WACzF;AASD,YAPA,EAAY,SAAQ,MAAS;MAC3B,IAAM,IAAc,EAAM,MAAM,IAAI,CAAC,KAAK,IAAI;AAC9C,QAAgB,KAAe,OAAO,EAAK,MAAW,WAClD,WAAW,EAAK,GAAO,GACtB,EAAK,MAAU;OACpB,EAEK;MACP,EAEF,IAAa,EAAY,KAAI,MAAS,EAAM,MAAM,IAAI,CAAC,KAAK,IAAI,EAAM;SAStE,CANA,IAAY,EAAK,KAAI,OAAS;IAC5B,MAAM,OAAO,EAAK,EAAK,OAAO,UAAU;IACxC,OAAO,OAAO,EAAK,EAAY,OAAQ,WACnC,WAAW,EAAK,EAAY,IAAI,GAC/B,EAAK,EAAY,OAAO;IAC9B,EAAE,EACH,IAAa,CAAC,QAAQ;;AAgB1B,SAXI,CAAC,KAAa,EAAU,WAAW,IAEnC,kBAAC,OAAD;GAAK,WAAU;GAAyE,OAAO,EAAE,WAAQ;aACvG,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAuC,EAAE,4BAA4B;KAAO,CAAA,EAC3F,kBAAC,OAAD;KAAK,WAAU;eAAoC;KAA+D,CAAA,CAC9G;;GACF,CAAA,GAKR,kBAAC,GAAD;GAAwB;aACtB,kBAAC,GAAD;IAAoB,MAAM;IAAW,QAAQ;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAI,MAAM;KAAI;IAAE,oBAAoB;cAA/G;KACG,EAAkB,YACjB,kBAAC,GAAD,EAAa,CAAA;KAEf,kBAAC,GAAD;MACE,SAAQ;MACR,MAAM,EAAE,UAAU,IAAI;MACtB,WAAU;MACV,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,EAAE,UAAU,IAAI;MACtB,WAAU;MACV,eAAe,EAAkB,mBAC5B,MAAe,EAAgB,GAAO,EAAkB,gBAAgB,GACzE,KAAA;MAEJ,CAAA;KACD,EAAkB,eACjB,kBAAC,GAAD,EACE,WAAW,EAAkB,mBACxB,GAAY,MAAiB,CAAC,EAAgB,GAAO,EAAkB,gBAAgB,EAAE,EAAK,GAC/F,KAAA,GAEJ,CAAA;KAEF,EAAkB,cAAc,EAAW,SAAS,KACpD,kBAAC,GAAD;MACE,cAAc;OAAE,UAAU;OAAQ,YAAY;OAAQ;MACtD,UAAS;MACT,UAAU;MACV,QAAO;MACP,OAAM;MACN,eAAc;MACd,eAAe,MAAM,EAAiB,OAAO,EAAE,WAAW,GAAG,CAAC;MAC9D,oBAAoB,EAAiB,KAAK;MAC1C,CAAA;KAEH,EAAW,KAAK,GAAW,MAC1B,kBAAC,GAAD;MAEE,MAAM;MACN,SAAS;MACT,QAAS,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WAAY,EAAa,IAAQ,EAAa;MAC/H,MAAO,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WAAY,EAAa,IAAQ,EAAa;MAC7H,aAAa,IAAiB,MAAkB,IAAY,KAAM,KAAO;MACzE,eAAe,IAAiB,MAAkB,IAAY,IAAI,KAAO;MACzE,aAAa;MACb,EARK,EAQL,CACF;KACiB;;GACN,CAAA;UAEZ,GAAO;AAEd,SACE,kBAAC,OAAD;GAAK,WAAU;GAAuF,OAAO,EAAE,WAAQ;aACrH,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAuC,EAAE,4BAA4B,EAAE,WAAW,eAAe,CAAC;MAAO,CAAA;KACxH,kBAAC,OAAD;MAAK,WAAU;gBAAsB,aAAiB,QAAQ,EAAM,UAAU,EAAE,6BAA6B;MAAO,CAAA;KACpH,kBAAC,OAAD;MAAK,WAAU;gBAAiC,EAAE,4BAA4B;MAAO,CAAA;KACjF;;GACF,CAAA;;EAGV"}
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CCl2IeXn.js";
2
2
  import { S as t, k as n, n as r, x as i, y as a } from "./chart-activity-grid-CWT0gLv4.js";
3
- import { c as o, l as s } from "./chart-area-D63kG8OT.js";
3
+ import { c as o, l as s } from "./chart-area-DDti9Qtp.js";
4
4
  import c, { useState as l } from "react";
5
5
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
6
  import { Cell as f, Legend as p, RadialBar as m, RadialBarChart as h } from "recharts";
@@ -145,4 +145,4 @@ var g = /* @__PURE__ */ e({ default: () => _ }), _ = c.memo(function({ data: e,
145
145
  //#endregion
146
146
  export { g as n, _ as t };
147
147
 
148
- //# sourceMappingURL=chart-radial-bar-Du7XNnwE.js.map
148
+ //# sourceMappingURL=chart-radial-bar-lla_JEYu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-radial-bar-Du7XNnwE.js","names":[],"sources":["../../../src/client/components/charts/RadialBarChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { RadialBarChart as RechartsRadialBarChart, RadialBar, Legend, Cell } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps } from '../../types'\n\nconst RadialBarChart = React.memo(function RadialBarChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n \n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\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.radialBar')}</div>\n </div>\n </div>\n )\n }\n\n let radialData: Array<{name: string, value: number, fill?: string}>\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Name/category field\n const yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis // Value field\n\n const granularity = getFieldGranularity(queryObject, xAxisField)\n radialData = data.map((item, index) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n value: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }))\n } else {\n // Legacy format or auto-detection\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find name/label field\n const nameField = keys.find(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 // Find a numeric field for values\n const valueField = keys.find(key => \n typeof firstRow[key] === 'number' && key !== nameField\n ) || keys[1]\n\n if (!valueField) {\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\">{t('chart.runtime.configErrorHint.radialBarNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for radial bar chart\n radialData = data.map((item, index) => {\n let name = item[nameField]\n // Handle boolean values with better labels\n if (typeof name === 'boolean') {\n name = name ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n } else {\n name = String(name)\n }\n return {\n name,\n value: typeof item[valueField] === 'string' \n ? parseFloat(item[valueField]) \n : (item[valueField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }\n })\n }\n\n // Filter out zero/null values\n radialData = radialData.filter(item => item.value != null && item.value !== 0)\n \n if (radialData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for radial bar chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsRadialBarChart\n data={radialData}\n innerRadius=\"10%\"\n outerRadius=\"80%\"\n margin={{ top: 20, right: 30, bottom: 20, left: 30 }}\n accessibilityLayer={false}\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 {safeDisplayConfig.showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.value || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n <RadialBar\n dataKey=\"value\"\n cornerRadius={4}\n label={{\n position: 'insideStart',\n fill: '#fff',\n fontSize: 12,\n formatter: safeDisplayConfig.leftYAxisFormat\n ? (value: any) => formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : undefined\n }}\n >\n {radialData.map((entry, index) => (\n <Cell \n key={`cell-${index}`} \n fill={entry.fill}\n fillOpacity={hoveredLegend ? (hoveredLegend === entry.name ? 1 : 0.3) : 1}\n />\n ))}\n </RadialBar>\n </RechartsRadialBarChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'RadialBarChart rendering 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: 'Radial Bar 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 RadialBarChart"],"mappings":"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"}
1
+ {"version":3,"file":"chart-radial-bar-lla_JEYu.js","names":[],"sources":["../../../src/client/components/charts/RadialBarChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { RadialBarChart as RechartsRadialBarChart, RadialBar, Legend, Cell } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps } from '../../types'\n\nconst RadialBarChart = React.memo(function RadialBarChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n \n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\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.radialBar')}</div>\n </div>\n </div>\n )\n }\n\n let radialData: Array<{name: string, value: number, fill?: string}>\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Name/category field\n const yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis // Value field\n\n const granularity = getFieldGranularity(queryObject, xAxisField)\n radialData = data.map((item, index) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n value: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }))\n } else {\n // Legacy format or auto-detection\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find name/label field\n const nameField = keys.find(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 // Find a numeric field for values\n const valueField = keys.find(key => \n typeof firstRow[key] === 'number' && key !== nameField\n ) || keys[1]\n\n if (!valueField) {\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\">{t('chart.runtime.configErrorHint.radialBarNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for radial bar chart\n radialData = data.map((item, index) => {\n let name = item[nameField]\n // Handle boolean values with better labels\n if (typeof name === 'boolean') {\n name = name ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n } else {\n name = String(name)\n }\n return {\n name,\n value: typeof item[valueField] === 'string' \n ? parseFloat(item[valueField]) \n : (item[valueField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }\n })\n }\n\n // Filter out zero/null values\n radialData = radialData.filter(item => item.value != null && item.value !== 0)\n \n if (radialData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for radial bar chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsRadialBarChart\n data={radialData}\n innerRadius=\"10%\"\n outerRadius=\"80%\"\n margin={{ top: 20, right: 30, bottom: 20, left: 30 }}\n accessibilityLayer={false}\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 {safeDisplayConfig.showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.value || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n <RadialBar\n dataKey=\"value\"\n cornerRadius={4}\n label={{\n position: 'insideStart',\n fill: '#fff',\n fontSize: 12,\n formatter: safeDisplayConfig.leftYAxisFormat\n ? (value: any) => formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : undefined\n }}\n >\n {radialData.map((entry, index) => (\n <Cell \n key={`cell-${index}`} \n fill={entry.fill}\n fillOpacity={hoveredLegend ? (hoveredLegend === entry.name ? 1 : 0.3) : 1}\n />\n ))}\n </RadialBar>\n </RechartsRadialBarChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'RadialBarChart rendering 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: 'Radial Bar 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 RadialBarChart"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CCl2IeXn.js";
2
2
  import { S as t, T as n, _ as r, i, k as a, n as o, w as s, x as c, y as l } from "./chart-activity-grid-CWT0gLv4.js";
3
- import { l as u } from "./chart-area-D63kG8OT.js";
3
+ import { l as u } from "./chart-area-DDti9Qtp.js";
4
4
  import d, { useState as f } from "react";
5
5
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
6
6
  import { CartesianGrid as h, Legend as g, Scatter as _, ScatterChart as v, Tooltip as y, XAxis as b, YAxis as x } from "recharts";
@@ -252,4 +252,4 @@ var S = /* @__PURE__ */ e({ default: () => C }), C = d.memo(function({ data: e,
252
252
  //#endregion
253
253
  export { S as n, C as t };
254
254
 
255
- //# sourceMappingURL=chart-scatter-D8krEYsA.js.map
255
+ //# sourceMappingURL=chart-scatter-DwXnI0rr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-scatter-D8krEYsA.js","names":[],"sources":["../../../src/client/components/charts/ScatterChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { ScatterChart as RechartsScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Legend, Tooltip } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, parseNumericValue, isValidNumericValue, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst ScatterChart = React.memo(function ScatterChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | 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 showLegend: displayConfig?.showLegend ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n showTooltip: displayConfig?.showTooltip ?? true\n }\n\n // Extract axis format configs\n // For scatter charts, xAxis uses xAxisFormat, yAxis uses leftYAxisFormat\n const xAxisFormat = displayConfig?.xAxisFormat\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\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.scatter')}</div>\n </div>\n </div>\n )\n }\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: string\n let yAxisField: string\n let seriesFields: string[] = []\n \n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - handle both string and array values\n xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis\n yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis\n // Normalize series to array\n const seriesConfig = chartConfig.series\n seriesFields = seriesConfig ? (Array.isArray(seriesConfig) ? seriesConfig : [seriesConfig]) : []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format (adapt for scatter chart)\n xAxisField = chartConfig.x\n yAxisField = Array.isArray(chartConfig.y) ? chartConfig.y[0] : chartConfig.y\n } else {\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\">{t('chart.runtime.configErrorHint.axisInvalid')}</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || !yAxisField) {\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\">{t('chart.runtime.configErrorHint.axisFields')}</div>\n </div>\n </div>\n )\n }\n\n // Extract time dimensions from query for tooltip display\n const timeDimensions = queryObject?.timeDimensions || []\n const timeDimensionFields = timeDimensions.map((td: any) => td.dimension)\n\n // Transform data for scatter plot\n // Null handling: Filter out data points where x or y coordinates are null\n let scatterData: any[]\n let seriesGroups: { [key: string]: any[] } = {}\n\n if (seriesFields.length > 0) {\n // Group data by series field\n const seriesField = seriesFields[0]\n data.forEach(item => {\n const seriesValue = String(item[seriesField] || 'Default')\n if (!seriesGroups[seriesValue]) {\n seriesGroups[seriesValue] = []\n }\n\n const xGranularity = getFieldGranularity(queryObject, xAxisField)\n const xValue = formatTimeValue(item[xAxisField], xGranularity) || item[xAxisField]\n const yValue = parseNumericValue(item[yAxisField])\n\n // Only add point if both x and y are valid numbers\n const xNum = typeof xValue === 'string' ? parseFloat(xValue) : xValue\n if (isValidNumericValue(xNum) && yValue !== null) {\n // Extract time dimension values for tooltip\n const timeValues: { [key: string]: string } = {}\n timeDimensionFields.forEach((field: string) => {\n if (item[field]) {\n const granularity = getFieldGranularity(queryObject, field)\n timeValues[field] = formatTimeValue(item[field], granularity)\n }\n })\n\n seriesGroups[seriesValue].push({\n x: xNum,\n y: yValue,\n name: seriesValue,\n timeValues,\n originalItem: item\n })\n }\n })\n\n // Collect all valid points from all series for validation\n // (The actual rendering uses seriesGroups with series separated)\n const seriesKeys = Object.keys(seriesGroups)\n scatterData = seriesKeys.flatMap(key => seriesGroups[key])\n } else {\n // Single series scatter plot\n const xGranularity = getFieldGranularity(queryObject, xAxisField)\n scatterData = data\n .map(item => {\n const xValue = formatTimeValue(item[xAxisField], xGranularity) || item[xAxisField]\n const yValue = parseNumericValue(item[yAxisField])\n const xNum = typeof xValue === 'string' ? parseFloat(xValue) : xValue\n\n // Extract time dimension values for tooltip\n const timeValues: { [key: string]: string } = {}\n timeDimensionFields.forEach((field: string) => {\n if (item[field]) {\n const granularity = getFieldGranularity(queryObject, field)\n timeValues[field] = formatTimeValue(item[field], granularity)\n }\n })\n\n return {\n x: xNum,\n y: yValue,\n name: `Point`,\n timeValues,\n originalItem: item,\n isValid: isValidNumericValue(xNum) && yValue !== null\n }\n })\n .filter(point => point.isValid)\n }\n \n // Validate transformed data\n if (!scatterData || scatterData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for scatter chart after transformation</div>\n </div>\n </div>\n )\n }\n\n const seriesKeys = Object.keys(seriesGroups)\n // Limit series to prevent performance issues with high-cardinality fields (e.g., dates)\n // If more than 20 unique series, fall back to single-series mode\n const MAX_SERIES = 20\n const hasSeries = seriesKeys.length > 1 && seriesKeys.length <= MAX_SERIES\n \n // Determine if legend will be shown\n const showLegend = safeDisplayConfig.showLegend && hasSeries\n \n // Use custom chart margins with extra left space for Y-axis label\n const chartMargins = {\n ...CHART_MARGINS,\n left: 40 // Increased from 20 to 40 for Y-axis label space\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsScatterChart margin={chartMargins} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <CartesianGrid strokeDasharray=\"3 3\" />\n )}\n <XAxis\n type=\"number\"\n dataKey=\"x\"\n name={xAxisFormat?.label || getFieldLabel(xAxisField)}\n tick={{ fontSize: 12 }}\n tickFormatter={xAxisFormat ? (value) => formatAxisValue(value, xAxisFormat) : undefined}\n />\n <YAxis\n type=\"number\"\n dataKey=\"y\"\n name={yAxisFormat?.label || getFieldLabel(yAxisField)}\n tick={{ fontSize: 12 }}\n tickFormatter={yAxisFormat ? (value) => formatAxisValue(value, yAxisFormat) : undefined}\n label={{ value: yAxisFormat?.label || getFieldLabel(yAxisField), angle: -90, position: 'left', style: { textAnchor: 'middle', fontSize: '12px' } }}\n />\n {safeDisplayConfig.showTooltip && (\n <Tooltip\n cursor={{ strokeDasharray: '3 3' }}\n content={({ active, payload }) => {\n if (!active || !payload || payload.length === 0) return null\n // Only show the first (active) point\n const point = payload[0]?.payload\n if (!point) return null\n\n return (\n <div style={{\n backgroundColor: 'white',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n fontSize: '0.875rem',\n color: '#1f2937',\n boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)',\n padding: '8px 12px'\n }}>\n <div style={{ fontWeight: 600, marginBottom: '4px' }}>{point.name}</div>\n {/* Show time dimension values if present */}\n {point.timeValues && Object.keys(point.timeValues).length > 0 && (\n <div style={{ marginBottom: '4px', color: '#6b7280' }}>\n {Object.entries(point.timeValues).map(([field, value]) => (\n <div key={field}>{getFieldLabel(field)}: {value as string}</div>\n ))}\n </div>\n )}\n <div>{xAxisFormat?.label || getFieldLabel(xAxisField)}: {formatAxisValue(point.x, xAxisFormat)}</div>\n <div>{yAxisFormat?.label || getFieldLabel(yAxisField)}: {formatAxisValue(point.y, yAxisFormat)}</div>\n </div>\n )\n }}\n />\n )}\n {showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {hasSeries ? (\n // Multiple series\n seriesKeys.map((seriesKey, index) => (\n <Scatter\n key={seriesKey}\n name={seriesKey}\n data={seriesGroups[seriesKey]}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n />\n ))\n ) : (\n // Single series\n <Scatter\n name=\"Data\"\n data={scatterData}\n fill={(colorPalette?.colors && colorPalette.colors[0]) || CHART_COLORS[0]}\n />\n )}\n </RechartsScatterChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'ScatterChart rendering 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: 'Scatter 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 ScatterChart"],"mappings":"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"}
1
+ {"version":3,"file":"chart-scatter-DwXnI0rr.js","names":[],"sources":["../../../src/client/components/charts/ScatterChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { ScatterChart as RechartsScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Legend, Tooltip } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, parseNumericValue, isValidNumericValue, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst ScatterChart = React.memo(function ScatterChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredLegend, setHoveredLegend] = useState<string | 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 showLegend: displayConfig?.showLegend ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n showTooltip: displayConfig?.showTooltip ?? true\n }\n\n // Extract axis format configs\n // For scatter charts, xAxis uses xAxisFormat, yAxis uses leftYAxisFormat\n const xAxisFormat = displayConfig?.xAxisFormat\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\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.scatter')}</div>\n </div>\n </div>\n )\n }\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: string\n let yAxisField: string\n let seriesFields: string[] = []\n \n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - handle both string and array values\n xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis\n yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis\n // Normalize series to array\n const seriesConfig = chartConfig.series\n seriesFields = seriesConfig ? (Array.isArray(seriesConfig) ? seriesConfig : [seriesConfig]) : []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format (adapt for scatter chart)\n xAxisField = chartConfig.x\n yAxisField = Array.isArray(chartConfig.y) ? chartConfig.y[0] : chartConfig.y\n } else {\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\">{t('chart.runtime.configErrorHint.axisInvalid')}</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || !yAxisField) {\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\">{t('chart.runtime.configErrorHint.axisFields')}</div>\n </div>\n </div>\n )\n }\n\n // Extract time dimensions from query for tooltip display\n const timeDimensions = queryObject?.timeDimensions || []\n const timeDimensionFields = timeDimensions.map((td: any) => td.dimension)\n\n // Transform data for scatter plot\n // Null handling: Filter out data points where x or y coordinates are null\n let scatterData: any[]\n let seriesGroups: { [key: string]: any[] } = {}\n\n if (seriesFields.length > 0) {\n // Group data by series field\n const seriesField = seriesFields[0]\n data.forEach(item => {\n const seriesValue = String(item[seriesField] || 'Default')\n if (!seriesGroups[seriesValue]) {\n seriesGroups[seriesValue] = []\n }\n\n const xGranularity = getFieldGranularity(queryObject, xAxisField)\n const xValue = formatTimeValue(item[xAxisField], xGranularity) || item[xAxisField]\n const yValue = parseNumericValue(item[yAxisField])\n\n // Only add point if both x and y are valid numbers\n const xNum = typeof xValue === 'string' ? parseFloat(xValue) : xValue\n if (isValidNumericValue(xNum) && yValue !== null) {\n // Extract time dimension values for tooltip\n const timeValues: { [key: string]: string } = {}\n timeDimensionFields.forEach((field: string) => {\n if (item[field]) {\n const granularity = getFieldGranularity(queryObject, field)\n timeValues[field] = formatTimeValue(item[field], granularity)\n }\n })\n\n seriesGroups[seriesValue].push({\n x: xNum,\n y: yValue,\n name: seriesValue,\n timeValues,\n originalItem: item\n })\n }\n })\n\n // Collect all valid points from all series for validation\n // (The actual rendering uses seriesGroups with series separated)\n const seriesKeys = Object.keys(seriesGroups)\n scatterData = seriesKeys.flatMap(key => seriesGroups[key])\n } else {\n // Single series scatter plot\n const xGranularity = getFieldGranularity(queryObject, xAxisField)\n scatterData = data\n .map(item => {\n const xValue = formatTimeValue(item[xAxisField], xGranularity) || item[xAxisField]\n const yValue = parseNumericValue(item[yAxisField])\n const xNum = typeof xValue === 'string' ? parseFloat(xValue) : xValue\n\n // Extract time dimension values for tooltip\n const timeValues: { [key: string]: string } = {}\n timeDimensionFields.forEach((field: string) => {\n if (item[field]) {\n const granularity = getFieldGranularity(queryObject, field)\n timeValues[field] = formatTimeValue(item[field], granularity)\n }\n })\n\n return {\n x: xNum,\n y: yValue,\n name: `Point`,\n timeValues,\n originalItem: item,\n isValid: isValidNumericValue(xNum) && yValue !== null\n }\n })\n .filter(point => point.isValid)\n }\n \n // Validate transformed data\n if (!scatterData || scatterData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for scatter chart after transformation</div>\n </div>\n </div>\n )\n }\n\n const seriesKeys = Object.keys(seriesGroups)\n // Limit series to prevent performance issues with high-cardinality fields (e.g., dates)\n // If more than 20 unique series, fall back to single-series mode\n const MAX_SERIES = 20\n const hasSeries = seriesKeys.length > 1 && seriesKeys.length <= MAX_SERIES\n \n // Determine if legend will be shown\n const showLegend = safeDisplayConfig.showLegend && hasSeries\n \n // Use custom chart margins with extra left space for Y-axis label\n const chartMargins = {\n ...CHART_MARGINS,\n left: 40 // Increased from 20 to 40 for Y-axis label space\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsScatterChart margin={chartMargins} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <CartesianGrid strokeDasharray=\"3 3\" />\n )}\n <XAxis\n type=\"number\"\n dataKey=\"x\"\n name={xAxisFormat?.label || getFieldLabel(xAxisField)}\n tick={{ fontSize: 12 }}\n tickFormatter={xAxisFormat ? (value) => formatAxisValue(value, xAxisFormat) : undefined}\n />\n <YAxis\n type=\"number\"\n dataKey=\"y\"\n name={yAxisFormat?.label || getFieldLabel(yAxisField)}\n tick={{ fontSize: 12 }}\n tickFormatter={yAxisFormat ? (value) => formatAxisValue(value, yAxisFormat) : undefined}\n label={{ value: yAxisFormat?.label || getFieldLabel(yAxisField), angle: -90, position: 'left', style: { textAnchor: 'middle', fontSize: '12px' } }}\n />\n {safeDisplayConfig.showTooltip && (\n <Tooltip\n cursor={{ strokeDasharray: '3 3' }}\n content={({ active, payload }) => {\n if (!active || !payload || payload.length === 0) return null\n // Only show the first (active) point\n const point = payload[0]?.payload\n if (!point) return null\n\n return (\n <div style={{\n backgroundColor: 'white',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n fontSize: '0.875rem',\n color: '#1f2937',\n boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)',\n padding: '8px 12px'\n }}>\n <div style={{ fontWeight: 600, marginBottom: '4px' }}>{point.name}</div>\n {/* Show time dimension values if present */}\n {point.timeValues && Object.keys(point.timeValues).length > 0 && (\n <div style={{ marginBottom: '4px', color: '#6b7280' }}>\n {Object.entries(point.timeValues).map(([field, value]) => (\n <div key={field}>{getFieldLabel(field)}: {value as string}</div>\n ))}\n </div>\n )}\n <div>{xAxisFormat?.label || getFieldLabel(xAxisField)}: {formatAxisValue(point.x, xAxisFormat)}</div>\n <div>{yAxisFormat?.label || getFieldLabel(yAxisField)}: {formatAxisValue(point.y, yAxisFormat)}</div>\n </div>\n )\n }}\n />\n )}\n {showLegend && (\n <Legend \n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"circle\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {hasSeries ? (\n // Multiple series\n seriesKeys.map((seriesKey, index) => (\n <Scatter\n key={seriesKey}\n name={seriesKey}\n data={seriesGroups[seriesKey]}\n fill={(colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]}\n fillOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n />\n ))\n ) : (\n // Single series\n <Scatter\n name=\"Data\"\n data={scatterData}\n fill={(colorPalette?.colors && colorPalette.colors[0]) || CHART_COLORS[0]}\n />\n )}\n </RechartsScatterChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'ScatterChart rendering 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: 'Scatter 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 ScatterChart"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CCl2IeXn.js";
2
2
  import { S as t, _ as n, k as r, n as i, r as a, x as o, y as s } from "./chart-activity-grid-CWT0gLv4.js";
3
- import { c, l } from "./chart-area-D63kG8OT.js";
3
+ import { c, l } from "./chart-area-DDti9Qtp.js";
4
4
  import u, { useState as d } from "react";
5
5
  import { jsx as f, jsxs as p } from "react/jsx-runtime";
6
6
  import { Treemap as m } from "recharts";
@@ -295,4 +295,4 @@ var _ = /* @__PURE__ */ e({ default: () => v }), v = u.memo(function({ data: e,
295
295
  //#endregion
296
296
  export { _ as n, v as t };
297
297
 
298
- //# sourceMappingURL=chart-tree-map-C5C2iaWM.js.map
298
+ //# sourceMappingURL=chart-tree-map-DJHoA26f.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-tree-map-C5C2iaWM.js","names":[],"sources":["../../../src/client/components/charts/TreeMapChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { Treemap } from 'recharts'\nimport { scaleQuantize, scaleOrdinal } from 'd3'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\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 (\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.treemap')}</div>\n </div>\n </div>\n )\n }\n\n let treemapData: Array<{name: string, size: number, fill?: string, series?: string}>\n let isNumericSeries = false\n let seriesField: string | undefined\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Name/category field\n const yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis // Size field\n seriesField = Array.isArray(chartConfig.series) ? chartConfig.series[0] : chartConfig.series // Color grouping field\n\n const granularity = getFieldGranularity(queryObject, xAxisField)\n \n if (seriesField) {\n // Check if series field is numeric for color scaling\n const seriesValues = data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }).filter(val => !isNaN(val))\n \n isNumericSeries = seriesValues.length === data.length && seriesValues.every(val => typeof val === 'number')\n \n \n if (isNumericSeries) {\n // Use D3 quantize scale for better color distribution with small ranges\n const minValue = Math.min(...seriesValues)\n const maxValue = Math.max(...seriesValues)\n \n // Create D3 quantize color scale - maps continuous data to discrete color bands\n const colorScale = scaleQuantize<string>()\n .domain([minValue, maxValue])\n .range(CHART_COLORS_GRADIENT)\n \n treemapData = data.map((item) => {\n const seriesValue = typeof item[seriesField!] === 'string' \n ? parseFloat(item[seriesField!]) \n : item[seriesField!]\n \n const color = colorScale(seriesValue)\n \n return {\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: color,\n series: String(item[seriesField!])\n }\n })\n } else {\n // Use D3 ordinal color scale for categorical series\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 \n treemapData = data.map((item) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: colorScale(String(item[seriesField!])),\n series: String(item[seriesField!])\n }))\n }\n } else {\n // No series grouping - use index-based colors\n treemapData = data.map((item, index) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n } else {\n // Legacy format or auto-detection\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find name/label field\n const nameField = keys.find(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 // Find a numeric field for size - look for 'size' field first, then any numeric\n const sizeField = keys.find(key => key.toLowerCase().includes('size')) ||\n keys.find(key => \n typeof firstRow[key] === 'number' && key !== nameField\n ) || keys[1]\n\n if (!sizeField) {\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\">{t('chart.runtime.configErrorHint.treemapNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for treemap chart\n treemapData = data.map((item, index) => {\n let name = item[nameField]\n // Handle boolean values with better labels\n if (typeof name === 'boolean') {\n name = name ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n } else {\n name = String(name)\n }\n return {\n name,\n size: typeof item[sizeField] === 'string' \n ? parseFloat(item[sizeField]) \n : (item[sizeField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }\n })\n }\n\n // Filter out zero/null values and ensure positive sizes\n treemapData = treemapData.filter(item => item.size != null && item.size > 0)\n \n if (treemapData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for treemap chart after transformation</div>\n </div>\n </div>\n )\n }\n\n // Custom content renderer for treemap cells with HTML overlays\n const CustomizedContent = (props: any) => {\n const { x, y, width, height, index, name, size } = props\n\n if (width < 20 || height < 20) return null // Don't render content for 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 contain display 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 return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n style={{\n fill: treemapData[index]?.fill || ((colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]),\n fillOpacity: hoveredIndex !== null ? (hoveredIndex === index ? 1 : 0.6) : 0.8,\n stroke: '#fff',\n strokeWidth: 2,\n cursor: drillEnabled ? 'pointer' : 'default',\n pointerEvents: 'all' // Ensure rect captures click events\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 {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(size, safeDisplayConfig.leftYAxisFormat)\n : (typeof size === 'number' ? size.toLocaleString() : size)\n }\n </div>\n )}\n </div>\n </foreignObject>\n </g>\n )\n }\n\n // Check if we have series data for legend\n const hasSeriesData = treemapData.some(item => 'series' in item)\n const uniqueSeries = hasSeriesData \n ? [...new Set(treemapData.map(item => item.series).filter(Boolean))]\n : []\n \n // For numeric series, create a legend showing the color scale\n let legendPayload: any[] = []\n if (safeDisplayConfig.showLegend && seriesField) {\n \n if (isNumericSeries) {\n // Create color scale legend for numeric values\n const minValue = Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }))\n const maxValue = Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }))\n \n \n // Create legend entries showing color scale\n legendPayload = CHART_COLORS_GRADIENT.map((color, index) => {\n const ratio = index / (CHART_COLORS_GRADIENT.length - 1)\n const value = minValue + (maxValue - minValue) * ratio\n return {\n value: safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : value.toFixed(2),\n type: 'rect',\n color: color\n }\n })\n } else if (uniqueSeries.length > 1) {\n // Use categorical legend for non-numeric series\n legendPayload = uniqueSeries.map((series, index) => ({\n value: series,\n type: 'rect',\n color: CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n \n }\n\n // Calculate height adjustment for legend\n const hasLegend = safeDisplayConfig.showLegend && legendPayload.length > 0\n const adjustedHeight = hasLegend \n ? (typeof height === 'string' && height.includes('%') \n ? height \n : typeof height === 'number' \n ? height + 60 \n : `calc(${height} + 60px)`)\n : height\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 <div className=\"dc:flex dc:justify-center dc:items-center dc:mt-4 dc:pb-2\">\n {isNumericSeries ? (\n // Gradient legend for numeric series\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 {seriesField ? getFieldLabel(seriesField) : ''}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <span className=\"dc:text-xs text-dc-text-muted\">\n {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })), safeDisplayConfig.leftYAxisFormat)\n : Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })).toFixed(2)\n }\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 {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })), safeDisplayConfig.leftYAxisFormat)\n : Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })).toFixed(2)\n }\n </span>\n </div>\n </div>\n ) : (\n // Discrete legend for categorical series\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\n className=\"dc:w-3 dc:h-3 rounded-xs\"\n style={{ backgroundColor: item.color }}\n />\n <span className=\"dc:text-xs text-dc-text-muted\">\n {item.value}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )\n } catch (error) {\n // 'TreeMapChart rendering 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: 'TreeMap 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 TreeMapChart"],"mappings":"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"}
1
+ {"version":3,"file":"chart-tree-map-DJHoA26f.js","names":[],"sources":["../../../src/client/components/charts/TreeMapChart.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { Treemap } from 'recharts'\nimport { scaleQuantize, scaleOrdinal } from 'd3'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\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 (\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.treemap')}</div>\n </div>\n </div>\n )\n }\n\n let treemapData: Array<{name: string, size: number, fill?: string, series?: string}>\n let isNumericSeries = false\n let seriesField: string | undefined\n\n if (chartConfig?.xAxis && chartConfig?.yAxis) {\n // New format - use chart config\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis // Name/category field\n const yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis // Size field\n seriesField = Array.isArray(chartConfig.series) ? chartConfig.series[0] : chartConfig.series // Color grouping field\n\n const granularity = getFieldGranularity(queryObject, xAxisField)\n \n if (seriesField) {\n // Check if series field is numeric for color scaling\n const seriesValues = data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }).filter(val => !isNaN(val))\n \n isNumericSeries = seriesValues.length === data.length && seriesValues.every(val => typeof val === 'number')\n \n \n if (isNumericSeries) {\n // Use D3 quantize scale for better color distribution with small ranges\n const minValue = Math.min(...seriesValues)\n const maxValue = Math.max(...seriesValues)\n \n // Create D3 quantize color scale - maps continuous data to discrete color bands\n const colorScale = scaleQuantize<string>()\n .domain([minValue, maxValue])\n .range(CHART_COLORS_GRADIENT)\n \n treemapData = data.map((item) => {\n const seriesValue = typeof item[seriesField!] === 'string' \n ? parseFloat(item[seriesField!]) \n : item[seriesField!]\n \n const color = colorScale(seriesValue)\n \n return {\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: color,\n series: String(item[seriesField!])\n }\n })\n } else {\n // Use D3 ordinal color scale for categorical series\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 \n treemapData = data.map((item) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: colorScale(String(item[seriesField!])),\n series: String(item[seriesField!])\n }))\n }\n } else {\n // No series grouping - use index-based colors\n treemapData = data.map((item, index) => ({\n name: formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown',\n size: typeof item[yAxisField] === 'string' \n ? parseFloat(item[yAxisField]) \n : (item[yAxisField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n } else {\n // Legacy format or auto-detection\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n \n // Try to find name/label field\n const nameField = keys.find(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 // Find a numeric field for size - look for 'size' field first, then any numeric\n const sizeField = keys.find(key => key.toLowerCase().includes('size')) ||\n keys.find(key => \n typeof firstRow[key] === 'number' && key !== nameField\n ) || keys[1]\n\n if (!sizeField) {\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\">{t('chart.runtime.configErrorHint.treemapNumeric')}</div>\n </div>\n </div>\n )\n }\n\n // Transform data for treemap chart\n treemapData = data.map((item, index) => {\n let name = item[nameField]\n // Handle boolean values with better labels\n if (typeof name === 'boolean') {\n name = name ? 'Active' : 'Inactive'\n } else if (name === 'true' || name === 'false') {\n name = name === 'true' ? 'Active' : 'Inactive'\n } else {\n name = String(name)\n }\n return {\n name,\n size: typeof item[sizeField] === 'string' \n ? parseFloat(item[sizeField]) \n : (item[sizeField] || 0),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]\n }\n })\n }\n\n // Filter out zero/null values and ensure positive sizes\n treemapData = treemapData.filter(item => item.size != null && item.size > 0)\n \n if (treemapData.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.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for treemap chart after transformation</div>\n </div>\n </div>\n )\n }\n\n // Custom content renderer for treemap cells with HTML overlays\n const CustomizedContent = (props: any) => {\n const { x, y, width, height, index, name, size } = props\n\n if (width < 20 || height < 20) return null // Don't render content for 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 contain display 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 return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n style={{\n fill: treemapData[index]?.fill || ((colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) || CHART_COLORS[index % CHART_COLORS.length]),\n fillOpacity: hoveredIndex !== null ? (hoveredIndex === index ? 1 : 0.6) : 0.8,\n stroke: '#fff',\n strokeWidth: 2,\n cursor: drillEnabled ? 'pointer' : 'default',\n pointerEvents: 'all' // Ensure rect captures click events\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 {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(size, safeDisplayConfig.leftYAxisFormat)\n : (typeof size === 'number' ? size.toLocaleString() : size)\n }\n </div>\n )}\n </div>\n </foreignObject>\n </g>\n )\n }\n\n // Check if we have series data for legend\n const hasSeriesData = treemapData.some(item => 'series' in item)\n const uniqueSeries = hasSeriesData \n ? [...new Set(treemapData.map(item => item.series).filter(Boolean))]\n : []\n \n // For numeric series, create a legend showing the color scale\n let legendPayload: any[] = []\n if (safeDisplayConfig.showLegend && seriesField) {\n \n if (isNumericSeries) {\n // Create color scale legend for numeric values\n const minValue = Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }))\n const maxValue = Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n }))\n \n \n // Create legend entries showing color scale\n legendPayload = CHART_COLORS_GRADIENT.map((color, index) => {\n const ratio = index / (CHART_COLORS_GRADIENT.length - 1)\n const value = minValue + (maxValue - minValue) * ratio\n return {\n value: safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(value, safeDisplayConfig.leftYAxisFormat)\n : value.toFixed(2),\n type: 'rect',\n color: color\n }\n })\n } else if (uniqueSeries.length > 1) {\n // Use categorical legend for non-numeric series\n legendPayload = uniqueSeries.map((series, index) => ({\n value: series,\n type: 'rect',\n color: CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n \n }\n\n // Calculate height adjustment for legend\n const hasLegend = safeDisplayConfig.showLegend && legendPayload.length > 0\n const adjustedHeight = hasLegend \n ? (typeof height === 'string' && height.includes('%') \n ? height \n : typeof height === 'number' \n ? height + 60 \n : `calc(${height} + 60px)`)\n : height\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 <div className=\"dc:flex dc:justify-center dc:items-center dc:mt-4 dc:pb-2\">\n {isNumericSeries ? (\n // Gradient legend for numeric series\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 {seriesField ? getFieldLabel(seriesField) : ''}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <span className=\"dc:text-xs text-dc-text-muted\">\n {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })), safeDisplayConfig.leftYAxisFormat)\n : Math.min(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })).toFixed(2)\n }\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 {safeDisplayConfig.leftYAxisFormat\n ? formatAxisValue(Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })), safeDisplayConfig.leftYAxisFormat)\n : Math.max(...data.map(item => {\n const value = item[seriesField!]\n return typeof value === 'string' ? parseFloat(value) : value\n })).toFixed(2)\n }\n </span>\n </div>\n </div>\n ) : (\n // Discrete legend for categorical series\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\n className=\"dc:w-3 dc:h-3 rounded-xs\"\n style={{ backgroundColor: item.color }}\n />\n <span className=\"dc:text-xs text-dc-text-muted\">\n {item.value}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )\n } catch (error) {\n // 'TreeMapChart rendering 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: 'TreeMap 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 TreeMapChart"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CCl2IeXn.js";
2
2
  import { _ as t, i as n, k as r, y as i } from "./chart-activity-grid-CWT0gLv4.js";
3
- import { c as a, l as o, s } from "./chart-area-D63kG8OT.js";
3
+ import { c as a, l as o, s } from "./chart-area-DDti9Qtp.js";
4
4
  import c, { useMemo as l } from "react";
5
5
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
6
  import { Bar as f, CartesianGrid as p, Cell as m, ComposedChart as h, LabelList as g, Legend as _, Line as v, XAxis as y, YAxis as b } from "recharts";
@@ -234,4 +234,4 @@ var O = c.memo(function({ data: e, chartConfig: c, displayConfig: x = {}, height
234
234
  //#endregion
235
235
  export { x as t };
236
236
 
237
- //# sourceMappingURL=chart-waterfall-BGdPrJ5Y.js.map
237
+ //# sourceMappingURL=chart-waterfall-Y7c8csO5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-waterfall-BGdPrJ5Y.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-Y7c8csO5.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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"}
@@ -334,7 +334,7 @@ var n = (/* @__PURE__ */ e((/* @__PURE__ */ t(((e, t) => {
334
334
  }
335
335
  }
336
336
  function ge(e, t) {
337
- return t ? Number(t) : _e(e) ? 0 : 1;
337
+ return t ? Number(t) : +!_e(e);
338
338
  }
339
339
  function _e(e) {
340
340
  return me.includes(e.toLowerCase());
@@ -838,4 +838,4 @@ var n = (/* @__PURE__ */ e((/* @__PURE__ */ t(((e, t) => {
838
838
  //#endregion
839
839
  export { n as default };
840
840
 
841
- //# sourceMappingURL=core-DcfMGTVa.js.map
841
+ //# sourceMappingURL=core-Dk6z6kC0.js.map