drizzle-cube 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/charts.js +13 -13
- package/dist/client/chunks/{RetentionCombinedChart-7bGP_ozM.js → RetentionCombinedChart-BK8N-MOQ.js} +2 -2
- package/dist/client/chunks/{RetentionCombinedChart-7bGP_ozM.js.map → RetentionCombinedChart-BK8N-MOQ.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-BlCXpnDL.js → analysis-builder-CNBmAGAO.js} +8 -9
- package/dist/client/chunks/{analysis-builder-BlCXpnDL.js.map → analysis-builder-CNBmAGAO.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-BOYNJQY8.js → analysis-builder-shared-INGGwyTG.js} +6 -6
- package/dist/client/chunks/{analysis-builder-shared-BOYNJQY8.js.map → analysis-builder-shared-INGGwyTG.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-sUkuCJzm.js → chart-activity-grid-DvgTYQaE.js} +2 -2
- package/dist/client/chunks/{chart-activity-grid-sUkuCJzm.js.map → chart-activity-grid-DvgTYQaE.js.map} +1 -1
- package/dist/client/chunks/{chart-area-C4DIi9k_.js → chart-area-BKjd_STS.js} +3 -3
- package/dist/client/chunks/{chart-area-C4DIi9k_.js.map → chart-area-BKjd_STS.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-7ZleGCsN.js → chart-bar-DBI41w05.js} +2 -2
- package/dist/client/chunks/{chart-bar-7ZleGCsN.js.map → chart-bar-DBI41w05.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-D-auWIjP.js → chart-bubble-BD-1kneU.js} +2 -2
- package/dist/client/chunks/{chart-bubble-D-auWIjP.js.map → chart-bubble-BD-1kneU.js.map} +1 -1
- package/dist/client/chunks/{chart-config-markdown-DZxdGNVQ.js → chart-config-markdown-6fsr-U6_.js} +38 -8
- package/dist/client/chunks/chart-config-markdown-6fsr-U6_.js.map +1 -0
- package/dist/client/chunks/{chart-data-table-DW6VNGeW.js → chart-data-table-B74HLpAx.js} +3 -3
- package/dist/client/chunks/{chart-data-table-DW6VNGeW.js.map → chart-data-table-B74HLpAx.js.map} +1 -1
- package/dist/client/chunks/{chart-funnel-eUJApzmA.js → chart-funnel-DQ9cW6j9.js} +2 -2
- package/dist/client/chunks/{chart-funnel-eUJApzmA.js.map → chart-funnel-DQ9cW6j9.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-DR3O3GXx.js → chart-heat-map-CpIr4tbs.js} +2 -2
- package/dist/client/chunks/{chart-heat-map-DR3O3GXx.js.map → chart-heat-map-CpIr4tbs.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-Bp9Yrgyc.js → chart-kpi-delta-DPcSazD3.js} +3 -3
- package/dist/client/chunks/{chart-kpi-delta-Bp9Yrgyc.js.map → chart-kpi-delta-DPcSazD3.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-B3yvgbr-.js → chart-kpi-number-D62PzKZ1.js} +2 -2
- package/dist/client/chunks/{chart-kpi-number-B3yvgbr-.js.map → chart-kpi-number-D62PzKZ1.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text-D0TsUiaO.js → chart-kpi-text-B6Z5tFV1.js} +3 -3
- package/dist/client/chunks/{chart-kpi-text-D0TsUiaO.js.map → chart-kpi-text-B6Z5tFV1.js.map} +1 -1
- package/dist/client/chunks/{chart-line-C7VStgaJ.js → chart-line-Ds4BYA0K.js} +3 -3
- package/dist/client/chunks/{chart-line-C7VStgaJ.js.map → chart-line-Ds4BYA0K.js.map} +1 -1
- package/dist/client/chunks/chart-markdown-Rq6ORisB.js +276 -0
- package/dist/client/chunks/chart-markdown-Rq6ORisB.js.map +1 -0
- package/dist/client/chunks/{chart-pie-DPdYJSM3.js → chart-pie-BBrLh0iU.js} +2 -2
- package/dist/client/chunks/{chart-pie-DPdYJSM3.js.map → chart-pie-BBrLh0iU.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-DF6VNSiC.js → chart-radar-vr5FgjHT.js} +2 -2
- package/dist/client/chunks/{chart-radar-DF6VNSiC.js.map → chart-radar-vr5FgjHT.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-7Ttfz-kO.js → chart-radial-bar-BV_3Nm5P.js} +2 -2
- package/dist/client/chunks/{chart-radial-bar-7Ttfz-kO.js.map → chart-radial-bar-BV_3Nm5P.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-D86RYk9B.js → chart-sankey-CHROzr4S.js} +2 -2
- package/dist/client/chunks/{chart-sankey-D86RYk9B.js.map → chart-sankey-CHROzr4S.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-BUnIiLr_.js → chart-scatter-DbRTU3FG.js} +2 -2
- package/dist/client/chunks/{chart-scatter-BUnIiLr_.js.map → chart-scatter-DbRTU3FG.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-CsHlHfZQ.js → chart-sunburst-B-aPUzYL.js} +2 -2
- package/dist/client/chunks/{chart-sunburst-CsHlHfZQ.js.map → chart-sunburst-B-aPUzYL.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-DFAbkeo1.js → chart-tree-map-qY148fiC.js} +2 -2
- package/dist/client/chunks/{chart-tree-map-DFAbkeo1.js.map → chart-tree-map-qY148fiC.js.map} +1 -1
- package/dist/client/chunks/{chartConfigRegistry-DNEbwgTc.js → chartConfigRegistry-Di34paQH.js} +2 -2
- package/dist/client/chunks/{chartConfigRegistry-DNEbwgTc.js.map → chartConfigRegistry-Di34paQH.js.map} +1 -1
- package/dist/client/chunks/{charts-core-DAF1iT_h.js → charts-core-T8UglYyq.js} +224 -224
- package/dist/client/chunks/charts-core-T8UglYyq.js.map +1 -0
- package/dist/client/chunks/{charts-loader-7pEaEz-f.js → charts-loader-YnhJHubD.js} +21 -21
- package/dist/client/chunks/{charts-loader-7pEaEz-f.js.map → charts-loader-YnhJHubD.js.map} +1 -1
- package/dist/client/chunks/components-D0i1yQsk.js +9835 -0
- package/dist/client/chunks/components-D0i1yQsk.js.map +1 -0
- package/dist/client/chunks/{core-DGLxd5v5.js → core-D_8mkGpQ.js} +2 -2
- package/dist/client/chunks/{core-DGLxd5v5.js.map → core-D_8mkGpQ.js.map} +1 -1
- package/dist/client/chunks/{providers-D2xswCYu.js → providers-CgxXm6Ll.js} +2 -2
- package/dist/client/chunks/{providers-D2xswCYu.js.map → providers-CgxXm6Ll.js.map} +1 -1
- package/dist/client/chunks/{syntaxHighlighting-DAT9C6Ss.js → syntaxHighlighting-BQfjio-i.js} +2 -2
- package/dist/client/chunks/{syntaxHighlighting-DAT9C6Ss.js.map → syntaxHighlighting-BQfjio-i.js.map} +1 -1
- package/dist/client/chunks/{useDirtyStateTracking-CTS_m9mg.js → useDirtyStateTracking-Cu1HSjmo.js} +9 -9
- package/dist/client/chunks/{useDirtyStateTracking-CTS_m9mg.js.map → useDirtyStateTracking-Cu1HSjmo.js.map} +1 -1
- package/dist/client/chunks/{vendor-DfDLOfBe.js → vendor-AVsJ2ni0.js} +4 -4
- package/dist/client/chunks/{vendor-DfDLOfBe.js.map → vendor-AVsJ2ni0.js.map} +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisDisplayConfigPanel.d.ts +3 -1
- package/dist/client/components/FloatingEditToolbar.d.ts +3 -1
- package/dist/client/components/TextPortletModal.d.ts +12 -0
- package/dist/client/components.js +15 -352
- package/dist/client/components.js.map +1 -1
- package/dist/client/hooks/useDashboardHook.d.ts +7 -2
- package/dist/client/hooks.js +23 -23
- package/dist/client/index.js +8 -8
- package/dist/client/providers.js +1 -1
- package/dist/client/stores/dashboardStore.d.ts +14 -0
- package/dist/client/styles.css +1 -1
- package/dist/client/types.d.ts +3 -0
- package/dist/client/utils.js +6 -6
- package/dist/client-bundle-stats.html +1 -1
- package/package.json +1 -1
- package/dist/client/chunks/DashboardEditModal-BGDhxKg1.js +0 -9169
- package/dist/client/chunks/DashboardEditModal-BGDhxKg1.js.map +0 -1
- package/dist/client/chunks/chart-config-markdown-DZxdGNVQ.js.map +0 -1
- package/dist/client/chunks/chart-markdown-Cget3iEq.js +0 -257
- package/dist/client/chunks/chart-markdown-Cget3iEq.js.map +0 -1
- package/dist/client/chunks/charts-core-DAF1iT_h.js.map +0 -1
package/dist/client/chunks/{chart-kpi-number-B3yvgbr-.js.map → chart-kpi-number-D62PzKZ1.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-kpi-number-B3yvgbr-.js","sources":["../../../src/client/utils/periodUtils.ts","../../../src/client/components/DataHistogram.tsx","../../../src/client/components/charts/KpiNumber.tsx"],"sourcesContent":["/**\n * Utility functions for detecting incomplete time periods in KPI charts\n */\n\n/**\n * Get the end date of a period based on granularity\n * @param date - The date within the period\n * @param granularity - The time granularity (day, week, month, quarter, year)\n * @returns The end date of the period (end of day)\n */\nexport function getPeriodEndDate(date: Date, granularity: string): Date {\n const endDate = new Date(date)\n\n switch (granularity.toLowerCase()) {\n case 'day':\n // End of the same day\n endDate.setHours(23, 59, 59, 999)\n break\n\n case 'week': {\n // End of the week (Saturday, assuming week starts Sunday)\n const dayOfWeek = endDate.getDay()\n const daysUntilSaturday = 6 - dayOfWeek\n endDate.setDate(endDate.getDate() + daysUntilSaturday)\n endDate.setHours(23, 59, 59, 999)\n break\n }\n\n case 'month':\n // Last day of the month\n endDate.setMonth(endDate.getMonth() + 1, 0) // Set to day 0 of next month = last day of current month\n endDate.setHours(23, 59, 59, 999)\n break\n\n case 'quarter': {\n // Last day of the quarter\n const currentMonth = endDate.getMonth()\n const quarterEndMonth = Math.floor(currentMonth / 3) * 3 + 2 // 0->2, 3->5, 6->8, 9->11\n endDate.setMonth(quarterEndMonth + 1, 0) // Last day of quarter end month\n endDate.setHours(23, 59, 59, 999)\n break\n }\n\n case 'year':\n // December 31st\n endDate.setMonth(11, 31) // December 31\n endDate.setHours(23, 59, 59, 999)\n break\n\n default:\n // Unknown granularity - treat as complete\n endDate.setHours(23, 59, 59, 999)\n }\n\n return endDate\n}\n\n/**\n * Check if the last period in the data is complete based on granularity\n * @param lastDataPoint - The last data point in the sorted dataset\n * @param timeDimensionField - The field name containing the time value\n * @param granularity - The time granularity\n * @returns true if the period is complete, false if it's incomplete\n */\nexport function isLastPeriodComplete(\n lastDataPoint: any,\n timeDimensionField: string,\n granularity: string\n): boolean {\n if (!lastDataPoint || !timeDimensionField || !granularity) {\n return true // Assume complete if we can't determine\n }\n\n const timeValue = lastDataPoint[timeDimensionField]\n if (!timeValue) {\n return true // Assume complete if no time value\n }\n\n // Parse the time value\n const date = new Date(timeValue)\n if (isNaN(date.getTime())) {\n return true // Assume complete if invalid date\n }\n\n // Get the end of this period\n const periodEnd = getPeriodEndDate(date, granularity)\n\n // Compare with current time\n const now = new Date()\n\n // If the period end is in the future, the period is incomplete\n return periodEnd <= now\n}\n\n/**\n * Extract granularity from a query object\n * @param queryObject - The CubeQuery object\n * @param dimensionField - Optional specific dimension field to match\n * @returns The granularity string or null if not found\n */\nexport function getQueryGranularity(\n queryObject: any,\n dimensionField?: string\n): string | null {\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return null\n }\n\n // If a specific dimension field is provided, try to find its granularity\n if (dimensionField) {\n const matchingDim = queryObject.timeDimensions.find((td: any) =>\n td.dimension === dimensionField ||\n td.dimension?.includes(dimensionField) ||\n dimensionField?.includes(td.dimension)\n )\n if (matchingDim?.granularity) {\n return matchingDim.granularity\n }\n }\n\n // Fallback to first time dimension's granularity\n const firstTimeDim = queryObject.timeDimensions[0]\n return firstTimeDim?.granularity || null\n}\n\n/**\n * Filter data to exclude incomplete or last period\n * @param data - The data array sorted by time\n * @param timeDimensionField - The field containing time values\n * @param queryObject - The query object containing timeDimensions\n * @param useLastCompletePeriod - Whether to check for incomplete periods\n * @param skipLastPeriod - Whether to always skip the last period (overrides useLastCompletePeriod)\n * @returns Object with filtered data and whether filtering was applied\n */\nexport function filterIncompletePeriod(\n data: any[],\n timeDimensionField: string | undefined,\n queryObject: any,\n useLastCompletePeriod: boolean,\n skipLastPeriod: boolean = false\n): { filteredData: any[]; excludedIncompletePeriod: boolean; skippedLastPeriod: boolean; granularity: string | null } {\n // Default return - no filtering\n const noFilter = {\n filteredData: data,\n excludedIncompletePeriod: false,\n skippedLastPeriod: false,\n granularity: null\n }\n\n // Need at least 2 data points to filter\n if (data.length < 2) {\n return noFilter\n }\n\n const granularity = getQueryGranularity(queryObject, timeDimensionField)\n\n // If skipLastPeriod is enabled, always skip the last period\n if (skipLastPeriod) {\n return {\n filteredData: data.slice(0, -1),\n excludedIncompletePeriod: false,\n skippedLastPeriod: true,\n granularity\n }\n }\n\n // Skip incomplete period check if feature is disabled\n if (!useLastCompletePeriod) {\n return { ...noFilter, granularity }\n }\n\n // Skip if no time dimension field\n if (!timeDimensionField) {\n return { ...noFilter, granularity }\n }\n\n // Skip if no time dimensions in query\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return { ...noFilter, granularity }\n }\n\n if (!granularity) {\n return noFilter\n }\n\n // Check if last period is incomplete\n const lastRow = data[data.length - 1]\n if (!isLastPeriodComplete(lastRow, timeDimensionField, granularity)) {\n return {\n filteredData: data.slice(0, -1),\n excludedIncompletePeriod: true,\n skippedLastPeriod: false,\n granularity\n }\n }\n\n return { ...noFilter, granularity }\n}\n","\ninterface DataHistogramProps {\n /** Array of numeric values to create histogram from */\n values: number[]\n /** Minimum value in the dataset */\n min: number\n /** Maximum value in the dataset */\n max: number\n /** Color for the histogram bars */\n color?: string\n /** Number of buckets/bars to create (default: 12) */\n bucketCount?: number\n /** Height of the histogram in pixels (default: 32) */\n height?: number\n /** Format function for min/max labels */\n formatValue?: (value: number) => string\n /** Width of the histogram to match text above */\n width?: number\n /** Whether to show average indicator line (default: true) */\n showAverageIndicator?: boolean\n /** Target value to show as green line */\n targetValue?: number\n}\n\n/**\n * Reusable histogram component that shows the distribution of actual data values\n */\nexport default function DataHistogram({\n values,\n min,\n max,\n color = '#1f2937',\n bucketCount = 12,\n height = 32,\n formatValue = (val) => val.toString(),\n width,\n showAverageIndicator = true,\n targetValue\n}: DataHistogramProps) {\n // Create histogram buckets from actual data\n const buckets = new Array(bucketCount).fill(0)\n const range = max - min\n \n // Distribute actual values into buckets\n values.forEach(value => {\n if (range === 0) {\n // All values are the same, put everything in middle bucket\n buckets[Math.floor(bucketCount / 2)]++\n } else {\n // Calculate which bucket this value belongs to\n let bucketIndex = Math.floor(((value - min) / range) * (bucketCount - 1))\n // Clamp to valid bucket range\n bucketIndex = Math.max(0, Math.min(bucketCount - 1, bucketIndex))\n buckets[bucketIndex]++\n }\n })\n \n // Find max bucket count for normalization\n const maxBucketCount = Math.max(...buckets)\n \n // Calculate average for indicator positioning\n const average = values.reduce((sum, val) => sum + val, 0) / values.length\n \n // Calculate average position as percentage of histogram width\n const averagePosition = range === 0 ? 50 : ((average - min) / range) * 100\n \n // Calculate target position if target value is provided\n const targetPosition = targetValue !== undefined && range > 0 \n ? ((targetValue - min) / range) * 100 \n : null\n\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center\">\n {/* Horizontal bars representing actual data distribution */}\n <div \n className=\"dc:relative dc:flex dc:items-end dc:justify-center dc:space-x-0.5\" \n style={{ \n height: `${height}px`,\n width: width ? `${width}px` : '200px',\n minWidth: '200px'\n }}\n >\n {buckets.map((count, i) => {\n // Normalize height based on actual data frequency\n const normalizedHeight = maxBucketCount > 0 ? count / maxBucketCount : 0\n const minHeight = 0.1 // minimum height for empty buckets\n const displayHeight = count > 0 ? Math.max(minHeight, normalizedHeight) : minHeight\n \n return (\n <div\n key={i}\n className=\"dc:flex-1 dc:rounded-t-sm dc:transition-all dc:duration-300 dc:ease-out\"\n style={{\n height: `${displayHeight * height}px`,\n backgroundColor: color,\n opacity: count > 0 ? 0.7 + (normalizedHeight * 0.3) : 0.2 // higher opacity for buckets with data\n }}\n title={`${count} values in this range`} // tooltip showing actual count\n />\n )\n })}\n \n {/* Average indicator line */}\n {showAverageIndicator && (\n <div\n className=\"dc:absolute dc:top-0 dc:bottom-0 dc:pointer-events-none\"\n style={{\n left: `${averagePosition}%`,\n transform: 'translateX(-50%)',\n width: '2px',\n backgroundColor: '#ef4444',\n opacity: 0.8,\n zIndex: 10\n }}\n title={`Average: ${formatValue(average)}`}\n >\n {/* Small triangle at top to indicate average */}\n <div\n className=\"dc:absolute dc:-top-1\"\n style={{\n left: '50%',\n transform: 'translateX(-50%)',\n width: '0',\n height: '0',\n borderLeft: '4px solid transparent',\n borderRight: '4px solid transparent',\n borderTop: '6px solid #ef4444'\n }}\n />\n </div>\n )}\n \n {/* Target indicator line */}\n {targetPosition !== null && targetValue !== undefined && (\n <div\n className=\"dc:absolute dc:top-0 dc:bottom-0 dc:pointer-events-none\"\n style={{\n left: `${Math.max(0, Math.min(100, targetPosition))}%`,\n transform: 'translateX(-50%)',\n width: '2px',\n backgroundColor: '#10b981',\n opacity: 0.8,\n zIndex: 11\n }}\n title={`Target: ${formatValue(targetValue)}`}\n >\n {/* Small triangle at top to indicate target */}\n <div\n className=\"dc:absolute dc:-top-1\"\n style={{\n left: '50%',\n transform: 'translateX(-50%)',\n width: '0',\n height: '0',\n borderLeft: '4px solid transparent',\n borderRight: '4px solid transparent',\n borderTop: '6px solid #10b981'\n }}\n />\n </div>\n )}\n </div>\n \n {/* Min/Max values aligned with histogram width */}\n <div\n className=\"dc:flex dc:justify-between dc:mt-2 dc:text-xs text-dc-text-muted\"\n style={{\n width: width ? `${width}px` : '200px',\n minWidth: '200px'\n }}\n >\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n\n {/* Average indicator */}\n <div className=\"dc:text-center dc:mt-1 dc:text-xs text-dc-text-muted\">\n Average of {values.length} values\n </div>\n </div>\n )\n}","import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react'\nimport { Icon } from '@iconify/react'\nimport infoCircleIcon from '@iconify-icons/tabler/info-circle'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport DataHistogram from '../DataHistogram'\nimport { parseTargetValues, calculateVariance, formatVariance } from '../../utils/targetUtils'\nimport { filterIncompletePeriod } from '../../utils/periodUtils'\nimport type { ChartProps } from '../../types'\n\nconst KpiNumber = React.memo(function KpiNumber({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(32)\n const [textWidth, setTextWidth] = useState(250)\n const containerRef = useRef<HTMLDivElement>(null)\n const valueRef = useRef<HTMLDivElement>(null)\n\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Extract value field from chart config - handle both string and array formats\n const valueFields = useMemo(() => {\n if (!chartConfig?.yAxis) return []\n if (typeof chartConfig.yAxis === 'string') return [chartConfig.yAxis]\n if (Array.isArray(chartConfig.yAxis)) return chartConfig.yAxis\n return []\n }, [chartConfig?.yAxis])\n\n const valueField = valueFields[0] || '' // Use first measure field\n\n // Get time dimension field if present (for incomplete period filtering)\n const timeDimensionField = queryObject?.timeDimensions?.[0]?.dimension || undefined\n\n // Memoize sorted data to prevent recalculation on every render\n const sortedData = useMemo(() => {\n if (!data || data.length === 0) return []\n let sorted = [...data]\n if (timeDimensionField) {\n sorted = sorted.sort((a, b) => {\n const aVal = a[timeDimensionField]\n const bVal = b[timeDimensionField]\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n })\n }\n return sorted\n }, [data, timeDimensionField])\n\n // Filter out incomplete or last period if enabled\n const { useLastCompletePeriod = true, skipLastPeriod = false } = displayConfig\n\n // Memoize filtered data\n const {\n filteredData,\n excludedIncompletePeriod,\n skippedLastPeriod,\n granularity\n } = useMemo(() => {\n if (sortedData.length === 0) {\n return { filteredData: [], excludedIncompletePeriod: false, skippedLastPeriod: false, granularity: undefined }\n }\n return filterIncompletePeriod(sortedData, timeDimensionField, queryObject, useLastCompletePeriod, skipLastPeriod)\n }, [sortedData, timeDimensionField, queryObject, useLastCompletePeriod, skipLastPeriod])\n\n // Use filtered data for calculations\n const dataToUse = filteredData\n\n // Memoize value extraction to prevent recalculation\n const values = useMemo(() => {\n if (!valueField || dataToUse.length === 0) return []\n\n const rawValues = dataToUse.map(row => {\n // Try direct field access first\n if (row[valueField] !== undefined) {\n return row[valueField]\n }\n\n // If not found, try finding the first numeric field as fallback\n const numericFields = Object.keys(row).filter(key =>\n typeof row[key] === 'number' && !isNaN(row[key])\n )\n\n if (numericFields.length > 0) {\n return row[numericFields[0]]\n }\n\n return undefined\n })\n\n return rawValues\n .filter(val => val !== null && val !== undefined && !isNaN(Number(val)))\n .map(val => Number(val))\n }, [dataToUse, valueField])\n\n // Memoize statistics calculations\n const { avg, min, max } = useMemo(() => {\n if (values.length === 0) return { avg: 0, min: 0, max: 0 }\n const sum = values.reduce((acc, val) => acc + val, 0)\n const avg = sum / values.length\n const min = Math.min(...values)\n const max = Math.max(...values)\n return { avg, min, max }\n }, [values])\n\n // Memoize format function to prevent re-creating on every render\n const formatNumber = useCallback((value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value)\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return '—'\n }\n\n const decimals = displayConfig.decimals ?? 0\n const prefix = displayConfig.prefix ?? ''\n\n let formattedValue: string\n\n if (Math.abs(value) >= 1e9) {\n formattedValue = (value / 1e9).toFixed(decimals) + 'B'\n } else if (Math.abs(value) >= 1e6) {\n formattedValue = (value / 1e6).toFixed(decimals) + 'M'\n } else if (Math.abs(value) >= 1e3) {\n formattedValue = (value / 1e3).toFixed(decimals) + 'K'\n } else {\n formattedValue = value.toFixed(decimals)\n }\n\n return prefix + formattedValue\n }, [displayConfig])\n\n const mainValue = values.length === 1 ? values[0] : avg\n const showStats = values.length > 1\n\n // Memoize color calculation to prevent re-creating function on every render\n const valueColor = useMemo((): string => {\n if (displayConfig.valueColorIndex !== undefined && colorPalette?.colors) {\n const colorIndex = displayConfig.valueColorIndex\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex]\n }\n }\n // Default to first color in palette if available, otherwise fallback to dark gray\n return colorPalette?.colors?.[0] || '#1f2937'\n }, [displayConfig.valueColorIndex, colorPalette?.colors])\n\n // Process target values for variance calculation\n const targetValues = useMemo(() => parseTargetValues(displayConfig?.target || ''), [displayConfig?.target])\n const targetValue = targetValues.length > 0 ? targetValues[0] : null // Use first target value\n const variance = targetValue !== null && values.length > 0 ? calculateVariance(mainValue, targetValue) : null\n\n // Memoize variance color calculation\n const varianceColor = useMemo((): string => {\n if (variance === null) return '#6B7280' // Gray for no target\n\n if (variance >= 0) {\n // Positive variance - use positive color from palette\n const positiveIndex = displayConfig.positiveColorIndex ?? 1\n return colorPalette?.colors?.[positiveIndex] || '#10B981' // Green fallback\n } else {\n // Negative variance - use negative color from palette\n const negativeIndex = displayConfig.negativeColorIndex ?? 7\n return colorPalette?.colors?.[negativeIndex] || '#EF4444' // Red fallback\n }\n }, [variance, displayConfig.positiveColorIndex, displayConfig.negativeColorIndex, colorPalette?.colors])\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const containerWidth = rect.width\n const containerHeight = rect.height\n\n if (containerWidth > 0 && containerHeight > 0) {\n // Calculate font size based on container dimensions\n // For KPI displays, we want the text to be large and prominent\n // Reserve space for the label by using more conservative sizing\n const widthBasedSize = containerWidth / 5\n const heightBasedSize = containerHeight / 4 // More conservative to leave room for label\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize)\n const clampedFontSize = Math.max(24, Math.min(baseFontSize, 120)) // Lower max to ensure label fits\n setFontSize(clampedFontSize)\n\n // Use a timeout to measure text width after font size is applied\n setTimeout(() => {\n if (valueRef.current) {\n const textRect = valueRef.current.getBoundingClientRect()\n const measuredWidth = textRect.width\n // Ensure we have a minimum width and use container width as fallback\n const effectiveWidth = Math.max(measuredWidth, Math.min(containerWidth * 0.6, 300))\n setTextWidth(effectiveWidth)\n }\n }, 10)\n }\n }\n }\n\n // Initial calculation - reduce delay for faster initial render\n const timer = setTimeout(updateDimensions, 50)\n\n const resizeObserver = new ResizeObserver(() => {\n // Debounce the resize updates\n setTimeout(updateDimensions, 10)\n })\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n return () => {\n clearTimeout(timer)\n resizeObserver.disconnect()\n }\n }, [data, chartConfig])\n\n // Early returns AFTER all hooks\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display</div>\n </div>\n </div>\n )\n }\n\n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-danger-bg)',\n color: 'var(--dc-danger)',\n borderColor: 'var(--dc-danger-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure fields configured</div>\n </div>\n </div>\n )\n }\n\n // Null handling: If all values are null, show placeholder instead of error\n if (values.length === 0) {\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Field Label */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-3\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2'\n }}\n >\n {getFieldLabel(valueField)}\n </div>\n\n {/* No Data Placeholder */}\n <div\n className=\"dc:font-bold dc:leading-none text-dc-text-muted\"\n style={{\n fontSize: `${fontSize}px`\n }}\n >\n —\n </div>\n\n <div className=\"dc:text-xs text-dc-text-muted dc:mt-2\">No data</div>\n </div>\n )\n }\n\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Field Label - Bolder and bigger */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-3 dc:flex dc:items-center dc:justify-center dc:gap-1\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2'\n }}\n >\n <span>\n {(() => {\n const label = getFieldLabel(valueField)\n // Temporary fix: if label seems wrong, use the field name directly\n const displayLabel = (label && label.length > 1) ? label : valueField\n return displayLabel\n })()}\n </span>\n {(excludedIncompletePeriod || skippedLastPeriod) && (\n <span\n title={skippedLastPeriod\n ? `Excludes last ${granularity || 'period'}`\n : `Excludes current incomplete ${granularity}`}\n className=\"dc:cursor-help\"\n >\n <Icon icon={infoCircleIcon} className=\"dc:w-4 dc:h-4 text-dc-text-muted dc:opacity-70\" />\n </span>\n )}\n </div>\n\n {/* Main KPI Value and Variance - Horizontal layout */}\n <div className=\"dc:flex dc:items-center dc:justify-center dc:gap-4 dc:mb-3\">\n <div\n ref={valueRef}\n className=\"dc:font-bold dc:leading-none\"\n style={{\n fontSize: `${fontSize}px`,\n color: valueColor\n }}\n >\n {formatNumber(mainValue)}\n </div>\n\n {/* Target Variance Display - To the right of main value */}\n {targetValue !== null && variance !== null && (\n <div className=\"dc:flex dc:flex-col dc:items-start\">\n <div\n className=\"dc:font-semibold\"\n style={{\n fontSize: `${Math.max(12, fontSize * 0.3)}px`,\n color: varianceColor,\n lineHeight: '1.2'\n }}\n >\n {formatVariance(variance, 1)}\n </div>\n <div\n className=\"text-dc-text-muted dc:text-xs\"\n style={{\n opacity: 0.7,\n fontSize: `${Math.max(10, fontSize * 0.2)}px`\n }}\n >\n vs {formatNumber(targetValue)}\n </div>\n </div>\n )}\n </div>\n\n {/* Unit/Suffix - Larger, not bold (hidden when formatValue is provided) */}\n {displayConfig.suffix && !displayConfig.formatValue && (\n <div\n className=\"text-dc-text-muted dc:text-center\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2',\n opacity: 0.8\n }}\n >\n {displayConfig.suffix}\n </div>\n )}\n\n {/* Data Histogram for multiple values */}\n {showStats && (\n <div className=\"dc:mt-4\">\n <DataHistogram\n values={values}\n min={min}\n max={max}\n color={valueColor}\n formatValue={formatNumber}\n height={24}\n width={textWidth}\n targetValue={targetValue || undefined}\n />\n </div>\n )}\n </div>\n )\n})\n\nexport default KpiNumber\n"],"names":["getPeriodEndDate","date","granularity","endDate","daysUntilSaturday","currentMonth","quarterEndMonth","isLastPeriodComplete","lastDataPoint","timeDimensionField","timeValue","getQueryGranularity","queryObject","dimensionField","matchingDim","td","filterIncompletePeriod","data","useLastCompletePeriod","skipLastPeriod","noFilter","lastRow","DataHistogram","values","min","max","color","bucketCount","height","formatValue","val","width","showAverageIndicator","targetValue","buckets","range","value","bucketIndex","maxBucketCount","average","sum","averagePosition","targetPosition","jsxs","count","i","normalizedHeight","minHeight","displayHeight","jsx","KpiNumber","React","chartConfig","displayConfig","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","valueRef","getFieldLabel","useCubeFieldLabel","valueFields","useMemo","valueField","sortedData","sorted","a","b","aVal","bVal","filteredData","excludedIncompletePeriod","skippedLastPeriod","dataToUse","row","numericFields","key","avg","acc","formatNumber","useCallback","decimals","prefix","formattedValue","mainValue","showStats","valueColor","colorIndex","targetValues","parseTargetValues","variance","calculateVariance","varianceColor","positiveIndex","negativeIndex","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","measuredWidth","effectiveWidth","timer","resizeObserver","label","Icon","infoCircleIcon","formatVariance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-kpi-number-D62PzKZ1.js","sources":["../../../src/client/utils/periodUtils.ts","../../../src/client/components/DataHistogram.tsx","../../../src/client/components/charts/KpiNumber.tsx"],"sourcesContent":["/**\n * Utility functions for detecting incomplete time periods in KPI charts\n */\n\n/**\n * Get the end date of a period based on granularity\n * @param date - The date within the period\n * @param granularity - The time granularity (day, week, month, quarter, year)\n * @returns The end date of the period (end of day)\n */\nexport function getPeriodEndDate(date: Date, granularity: string): Date {\n const endDate = new Date(date)\n\n switch (granularity.toLowerCase()) {\n case 'day':\n // End of the same day\n endDate.setHours(23, 59, 59, 999)\n break\n\n case 'week': {\n // End of the week (Saturday, assuming week starts Sunday)\n const dayOfWeek = endDate.getDay()\n const daysUntilSaturday = 6 - dayOfWeek\n endDate.setDate(endDate.getDate() + daysUntilSaturday)\n endDate.setHours(23, 59, 59, 999)\n break\n }\n\n case 'month':\n // Last day of the month\n endDate.setMonth(endDate.getMonth() + 1, 0) // Set to day 0 of next month = last day of current month\n endDate.setHours(23, 59, 59, 999)\n break\n\n case 'quarter': {\n // Last day of the quarter\n const currentMonth = endDate.getMonth()\n const quarterEndMonth = Math.floor(currentMonth / 3) * 3 + 2 // 0->2, 3->5, 6->8, 9->11\n endDate.setMonth(quarterEndMonth + 1, 0) // Last day of quarter end month\n endDate.setHours(23, 59, 59, 999)\n break\n }\n\n case 'year':\n // December 31st\n endDate.setMonth(11, 31) // December 31\n endDate.setHours(23, 59, 59, 999)\n break\n\n default:\n // Unknown granularity - treat as complete\n endDate.setHours(23, 59, 59, 999)\n }\n\n return endDate\n}\n\n/**\n * Check if the last period in the data is complete based on granularity\n * @param lastDataPoint - The last data point in the sorted dataset\n * @param timeDimensionField - The field name containing the time value\n * @param granularity - The time granularity\n * @returns true if the period is complete, false if it's incomplete\n */\nexport function isLastPeriodComplete(\n lastDataPoint: any,\n timeDimensionField: string,\n granularity: string\n): boolean {\n if (!lastDataPoint || !timeDimensionField || !granularity) {\n return true // Assume complete if we can't determine\n }\n\n const timeValue = lastDataPoint[timeDimensionField]\n if (!timeValue) {\n return true // Assume complete if no time value\n }\n\n // Parse the time value\n const date = new Date(timeValue)\n if (isNaN(date.getTime())) {\n return true // Assume complete if invalid date\n }\n\n // Get the end of this period\n const periodEnd = getPeriodEndDate(date, granularity)\n\n // Compare with current time\n const now = new Date()\n\n // If the period end is in the future, the period is incomplete\n return periodEnd <= now\n}\n\n/**\n * Extract granularity from a query object\n * @param queryObject - The CubeQuery object\n * @param dimensionField - Optional specific dimension field to match\n * @returns The granularity string or null if not found\n */\nexport function getQueryGranularity(\n queryObject: any,\n dimensionField?: string\n): string | null {\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return null\n }\n\n // If a specific dimension field is provided, try to find its granularity\n if (dimensionField) {\n const matchingDim = queryObject.timeDimensions.find((td: any) =>\n td.dimension === dimensionField ||\n td.dimension?.includes(dimensionField) ||\n dimensionField?.includes(td.dimension)\n )\n if (matchingDim?.granularity) {\n return matchingDim.granularity\n }\n }\n\n // Fallback to first time dimension's granularity\n const firstTimeDim = queryObject.timeDimensions[0]\n return firstTimeDim?.granularity || null\n}\n\n/**\n * Filter data to exclude incomplete or last period\n * @param data - The data array sorted by time\n * @param timeDimensionField - The field containing time values\n * @param queryObject - The query object containing timeDimensions\n * @param useLastCompletePeriod - Whether to check for incomplete periods\n * @param skipLastPeriod - Whether to always skip the last period (overrides useLastCompletePeriod)\n * @returns Object with filtered data and whether filtering was applied\n */\nexport function filterIncompletePeriod(\n data: any[],\n timeDimensionField: string | undefined,\n queryObject: any,\n useLastCompletePeriod: boolean,\n skipLastPeriod: boolean = false\n): { filteredData: any[]; excludedIncompletePeriod: boolean; skippedLastPeriod: boolean; granularity: string | null } {\n // Default return - no filtering\n const noFilter = {\n filteredData: data,\n excludedIncompletePeriod: false,\n skippedLastPeriod: false,\n granularity: null\n }\n\n // Need at least 2 data points to filter\n if (data.length < 2) {\n return noFilter\n }\n\n const granularity = getQueryGranularity(queryObject, timeDimensionField)\n\n // If skipLastPeriod is enabled, always skip the last period\n if (skipLastPeriod) {\n return {\n filteredData: data.slice(0, -1),\n excludedIncompletePeriod: false,\n skippedLastPeriod: true,\n granularity\n }\n }\n\n // Skip incomplete period check if feature is disabled\n if (!useLastCompletePeriod) {\n return { ...noFilter, granularity }\n }\n\n // Skip if no time dimension field\n if (!timeDimensionField) {\n return { ...noFilter, granularity }\n }\n\n // Skip if no time dimensions in query\n if (!queryObject?.timeDimensions || queryObject.timeDimensions.length === 0) {\n return { ...noFilter, granularity }\n }\n\n if (!granularity) {\n return noFilter\n }\n\n // Check if last period is incomplete\n const lastRow = data[data.length - 1]\n if (!isLastPeriodComplete(lastRow, timeDimensionField, granularity)) {\n return {\n filteredData: data.slice(0, -1),\n excludedIncompletePeriod: true,\n skippedLastPeriod: false,\n granularity\n }\n }\n\n return { ...noFilter, granularity }\n}\n","\ninterface DataHistogramProps {\n /** Array of numeric values to create histogram from */\n values: number[]\n /** Minimum value in the dataset */\n min: number\n /** Maximum value in the dataset */\n max: number\n /** Color for the histogram bars */\n color?: string\n /** Number of buckets/bars to create (default: 12) */\n bucketCount?: number\n /** Height of the histogram in pixels (default: 32) */\n height?: number\n /** Format function for min/max labels */\n formatValue?: (value: number) => string\n /** Width of the histogram to match text above */\n width?: number\n /** Whether to show average indicator line (default: true) */\n showAverageIndicator?: boolean\n /** Target value to show as green line */\n targetValue?: number\n}\n\n/**\n * Reusable histogram component that shows the distribution of actual data values\n */\nexport default function DataHistogram({\n values,\n min,\n max,\n color = '#1f2937',\n bucketCount = 12,\n height = 32,\n formatValue = (val) => val.toString(),\n width,\n showAverageIndicator = true,\n targetValue\n}: DataHistogramProps) {\n // Create histogram buckets from actual data\n const buckets = new Array(bucketCount).fill(0)\n const range = max - min\n \n // Distribute actual values into buckets\n values.forEach(value => {\n if (range === 0) {\n // All values are the same, put everything in middle bucket\n buckets[Math.floor(bucketCount / 2)]++\n } else {\n // Calculate which bucket this value belongs to\n let bucketIndex = Math.floor(((value - min) / range) * (bucketCount - 1))\n // Clamp to valid bucket range\n bucketIndex = Math.max(0, Math.min(bucketCount - 1, bucketIndex))\n buckets[bucketIndex]++\n }\n })\n \n // Find max bucket count for normalization\n const maxBucketCount = Math.max(...buckets)\n \n // Calculate average for indicator positioning\n const average = values.reduce((sum, val) => sum + val, 0) / values.length\n \n // Calculate average position as percentage of histogram width\n const averagePosition = range === 0 ? 50 : ((average - min) / range) * 100\n \n // Calculate target position if target value is provided\n const targetPosition = targetValue !== undefined && range > 0 \n ? ((targetValue - min) / range) * 100 \n : null\n\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center\">\n {/* Horizontal bars representing actual data distribution */}\n <div \n className=\"dc:relative dc:flex dc:items-end dc:justify-center dc:space-x-0.5\" \n style={{ \n height: `${height}px`,\n width: width ? `${width}px` : '200px',\n minWidth: '200px'\n }}\n >\n {buckets.map((count, i) => {\n // Normalize height based on actual data frequency\n const normalizedHeight = maxBucketCount > 0 ? count / maxBucketCount : 0\n const minHeight = 0.1 // minimum height for empty buckets\n const displayHeight = count > 0 ? Math.max(minHeight, normalizedHeight) : minHeight\n \n return (\n <div\n key={i}\n className=\"dc:flex-1 dc:rounded-t-sm dc:transition-all dc:duration-300 dc:ease-out\"\n style={{\n height: `${displayHeight * height}px`,\n backgroundColor: color,\n opacity: count > 0 ? 0.7 + (normalizedHeight * 0.3) : 0.2 // higher opacity for buckets with data\n }}\n title={`${count} values in this range`} // tooltip showing actual count\n />\n )\n })}\n \n {/* Average indicator line */}\n {showAverageIndicator && (\n <div\n className=\"dc:absolute dc:top-0 dc:bottom-0 dc:pointer-events-none\"\n style={{\n left: `${averagePosition}%`,\n transform: 'translateX(-50%)',\n width: '2px',\n backgroundColor: '#ef4444',\n opacity: 0.8,\n zIndex: 10\n }}\n title={`Average: ${formatValue(average)}`}\n >\n {/* Small triangle at top to indicate average */}\n <div\n className=\"dc:absolute dc:-top-1\"\n style={{\n left: '50%',\n transform: 'translateX(-50%)',\n width: '0',\n height: '0',\n borderLeft: '4px solid transparent',\n borderRight: '4px solid transparent',\n borderTop: '6px solid #ef4444'\n }}\n />\n </div>\n )}\n \n {/* Target indicator line */}\n {targetPosition !== null && targetValue !== undefined && (\n <div\n className=\"dc:absolute dc:top-0 dc:bottom-0 dc:pointer-events-none\"\n style={{\n left: `${Math.max(0, Math.min(100, targetPosition))}%`,\n transform: 'translateX(-50%)',\n width: '2px',\n backgroundColor: '#10b981',\n opacity: 0.8,\n zIndex: 11\n }}\n title={`Target: ${formatValue(targetValue)}`}\n >\n {/* Small triangle at top to indicate target */}\n <div\n className=\"dc:absolute dc:-top-1\"\n style={{\n left: '50%',\n transform: 'translateX(-50%)',\n width: '0',\n height: '0',\n borderLeft: '4px solid transparent',\n borderRight: '4px solid transparent',\n borderTop: '6px solid #10b981'\n }}\n />\n </div>\n )}\n </div>\n \n {/* Min/Max values aligned with histogram width */}\n <div\n className=\"dc:flex dc:justify-between dc:mt-2 dc:text-xs text-dc-text-muted\"\n style={{\n width: width ? `${width}px` : '200px',\n minWidth: '200px'\n }}\n >\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n\n {/* Average indicator */}\n <div className=\"dc:text-center dc:mt-1 dc:text-xs text-dc-text-muted\">\n Average of {values.length} values\n </div>\n </div>\n )\n}","import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react'\nimport { Icon } from '@iconify/react'\nimport infoCircleIcon from '@iconify-icons/tabler/info-circle'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport DataHistogram from '../DataHistogram'\nimport { parseTargetValues, calculateVariance, formatVariance } from '../../utils/targetUtils'\nimport { filterIncompletePeriod } from '../../utils/periodUtils'\nimport type { ChartProps } from '../../types'\n\nconst KpiNumber = React.memo(function KpiNumber({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(32)\n const [textWidth, setTextWidth] = useState(250)\n const containerRef = useRef<HTMLDivElement>(null)\n const valueRef = useRef<HTMLDivElement>(null)\n\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Extract value field from chart config - handle both string and array formats\n const valueFields = useMemo(() => {\n if (!chartConfig?.yAxis) return []\n if (typeof chartConfig.yAxis === 'string') return [chartConfig.yAxis]\n if (Array.isArray(chartConfig.yAxis)) return chartConfig.yAxis\n return []\n }, [chartConfig?.yAxis])\n\n const valueField = valueFields[0] || '' // Use first measure field\n\n // Get time dimension field if present (for incomplete period filtering)\n const timeDimensionField = queryObject?.timeDimensions?.[0]?.dimension || undefined\n\n // Memoize sorted data to prevent recalculation on every render\n const sortedData = useMemo(() => {\n if (!data || data.length === 0) return []\n let sorted = [...data]\n if (timeDimensionField) {\n sorted = sorted.sort((a, b) => {\n const aVal = a[timeDimensionField]\n const bVal = b[timeDimensionField]\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n })\n }\n return sorted\n }, [data, timeDimensionField])\n\n // Filter out incomplete or last period if enabled\n const { useLastCompletePeriod = true, skipLastPeriod = false } = displayConfig\n\n // Memoize filtered data\n const {\n filteredData,\n excludedIncompletePeriod,\n skippedLastPeriod,\n granularity\n } = useMemo(() => {\n if (sortedData.length === 0) {\n return { filteredData: [], excludedIncompletePeriod: false, skippedLastPeriod: false, granularity: undefined }\n }\n return filterIncompletePeriod(sortedData, timeDimensionField, queryObject, useLastCompletePeriod, skipLastPeriod)\n }, [sortedData, timeDimensionField, queryObject, useLastCompletePeriod, skipLastPeriod])\n\n // Use filtered data for calculations\n const dataToUse = filteredData\n\n // Memoize value extraction to prevent recalculation\n const values = useMemo(() => {\n if (!valueField || dataToUse.length === 0) return []\n\n const rawValues = dataToUse.map(row => {\n // Try direct field access first\n if (row[valueField] !== undefined) {\n return row[valueField]\n }\n\n // If not found, try finding the first numeric field as fallback\n const numericFields = Object.keys(row).filter(key =>\n typeof row[key] === 'number' && !isNaN(row[key])\n )\n\n if (numericFields.length > 0) {\n return row[numericFields[0]]\n }\n\n return undefined\n })\n\n return rawValues\n .filter(val => val !== null && val !== undefined && !isNaN(Number(val)))\n .map(val => Number(val))\n }, [dataToUse, valueField])\n\n // Memoize statistics calculations\n const { avg, min, max } = useMemo(() => {\n if (values.length === 0) return { avg: 0, min: 0, max: 0 }\n const sum = values.reduce((acc, val) => acc + val, 0)\n const avg = sum / values.length\n const min = Math.min(...values)\n const max = Math.max(...values)\n return { avg, min, max }\n }, [values])\n\n // Memoize format function to prevent re-creating on every render\n const formatNumber = useCallback((value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value)\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return '—'\n }\n\n const decimals = displayConfig.decimals ?? 0\n const prefix = displayConfig.prefix ?? ''\n\n let formattedValue: string\n\n if (Math.abs(value) >= 1e9) {\n formattedValue = (value / 1e9).toFixed(decimals) + 'B'\n } else if (Math.abs(value) >= 1e6) {\n formattedValue = (value / 1e6).toFixed(decimals) + 'M'\n } else if (Math.abs(value) >= 1e3) {\n formattedValue = (value / 1e3).toFixed(decimals) + 'K'\n } else {\n formattedValue = value.toFixed(decimals)\n }\n\n return prefix + formattedValue\n }, [displayConfig])\n\n const mainValue = values.length === 1 ? values[0] : avg\n const showStats = values.length > 1\n\n // Memoize color calculation to prevent re-creating function on every render\n const valueColor = useMemo((): string => {\n if (displayConfig.valueColorIndex !== undefined && colorPalette?.colors) {\n const colorIndex = displayConfig.valueColorIndex\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex]\n }\n }\n // Default to first color in palette if available, otherwise fallback to dark gray\n return colorPalette?.colors?.[0] || '#1f2937'\n }, [displayConfig.valueColorIndex, colorPalette?.colors])\n\n // Process target values for variance calculation\n const targetValues = useMemo(() => parseTargetValues(displayConfig?.target || ''), [displayConfig?.target])\n const targetValue = targetValues.length > 0 ? targetValues[0] : null // Use first target value\n const variance = targetValue !== null && values.length > 0 ? calculateVariance(mainValue, targetValue) : null\n\n // Memoize variance color calculation\n const varianceColor = useMemo((): string => {\n if (variance === null) return '#6B7280' // Gray for no target\n\n if (variance >= 0) {\n // Positive variance - use positive color from palette\n const positiveIndex = displayConfig.positiveColorIndex ?? 1\n return colorPalette?.colors?.[positiveIndex] || '#10B981' // Green fallback\n } else {\n // Negative variance - use negative color from palette\n const negativeIndex = displayConfig.negativeColorIndex ?? 7\n return colorPalette?.colors?.[negativeIndex] || '#EF4444' // Red fallback\n }\n }, [variance, displayConfig.positiveColorIndex, displayConfig.negativeColorIndex, colorPalette?.colors])\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const containerWidth = rect.width\n const containerHeight = rect.height\n\n if (containerWidth > 0 && containerHeight > 0) {\n // Calculate font size based on container dimensions\n // For KPI displays, we want the text to be large and prominent\n // Reserve space for the label by using more conservative sizing\n const widthBasedSize = containerWidth / 5\n const heightBasedSize = containerHeight / 4 // More conservative to leave room for label\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize)\n const clampedFontSize = Math.max(24, Math.min(baseFontSize, 120)) // Lower max to ensure label fits\n setFontSize(clampedFontSize)\n\n // Use a timeout to measure text width after font size is applied\n setTimeout(() => {\n if (valueRef.current) {\n const textRect = valueRef.current.getBoundingClientRect()\n const measuredWidth = textRect.width\n // Ensure we have a minimum width and use container width as fallback\n const effectiveWidth = Math.max(measuredWidth, Math.min(containerWidth * 0.6, 300))\n setTextWidth(effectiveWidth)\n }\n }, 10)\n }\n }\n }\n\n // Initial calculation - reduce delay for faster initial render\n const timer = setTimeout(updateDimensions, 50)\n\n const resizeObserver = new ResizeObserver(() => {\n // Debounce the resize updates\n setTimeout(updateDimensions, 10)\n })\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n return () => {\n clearTimeout(timer)\n resizeObserver.disconnect()\n }\n }, [data, chartConfig])\n\n // Early returns AFTER all hooks\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display</div>\n </div>\n </div>\n )\n }\n\n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-danger-bg)',\n color: 'var(--dc-danger)',\n borderColor: 'var(--dc-danger-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure fields configured</div>\n </div>\n </div>\n )\n }\n\n // Null handling: If all values are null, show placeholder instead of error\n if (values.length === 0) {\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Field Label */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-3\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2'\n }}\n >\n {getFieldLabel(valueField)}\n </div>\n\n {/* No Data Placeholder */}\n <div\n className=\"dc:font-bold dc:leading-none text-dc-text-muted\"\n style={{\n fontSize: `${fontSize}px`\n }}\n >\n —\n </div>\n\n <div className=\"dc:text-xs text-dc-text-muted dc:mt-2\">No data</div>\n </div>\n )\n }\n\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Field Label - Bolder and bigger */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-3 dc:flex dc:items-center dc:justify-center dc:gap-1\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2'\n }}\n >\n <span>\n {(() => {\n const label = getFieldLabel(valueField)\n // Temporary fix: if label seems wrong, use the field name directly\n const displayLabel = (label && label.length > 1) ? label : valueField\n return displayLabel\n })()}\n </span>\n {(excludedIncompletePeriod || skippedLastPeriod) && (\n <span\n title={skippedLastPeriod\n ? `Excludes last ${granularity || 'period'}`\n : `Excludes current incomplete ${granularity}`}\n className=\"dc:cursor-help\"\n >\n <Icon icon={infoCircleIcon} className=\"dc:w-4 dc:h-4 text-dc-text-muted dc:opacity-70\" />\n </span>\n )}\n </div>\n\n {/* Main KPI Value and Variance - Horizontal layout */}\n <div className=\"dc:flex dc:items-center dc:justify-center dc:gap-4 dc:mb-3\">\n <div\n ref={valueRef}\n className=\"dc:font-bold dc:leading-none\"\n style={{\n fontSize: `${fontSize}px`,\n color: valueColor\n }}\n >\n {formatNumber(mainValue)}\n </div>\n\n {/* Target Variance Display - To the right of main value */}\n {targetValue !== null && variance !== null && (\n <div className=\"dc:flex dc:flex-col dc:items-start\">\n <div\n className=\"dc:font-semibold\"\n style={{\n fontSize: `${Math.max(12, fontSize * 0.3)}px`,\n color: varianceColor,\n lineHeight: '1.2'\n }}\n >\n {formatVariance(variance, 1)}\n </div>\n <div\n className=\"text-dc-text-muted dc:text-xs\"\n style={{\n opacity: 0.7,\n fontSize: `${Math.max(10, fontSize * 0.2)}px`\n }}\n >\n vs {formatNumber(targetValue)}\n </div>\n </div>\n )}\n </div>\n\n {/* Unit/Suffix - Larger, not bold (hidden when formatValue is provided) */}\n {displayConfig.suffix && !displayConfig.formatValue && (\n <div\n className=\"text-dc-text-muted dc:text-center\"\n style={{\n fontSize: '14px',\n lineHeight: '1.2',\n opacity: 0.8\n }}\n >\n {displayConfig.suffix}\n </div>\n )}\n\n {/* Data Histogram for multiple values */}\n {showStats && (\n <div className=\"dc:mt-4\">\n <DataHistogram\n values={values}\n min={min}\n max={max}\n color={valueColor}\n formatValue={formatNumber}\n height={24}\n width={textWidth}\n targetValue={targetValue || undefined}\n />\n </div>\n )}\n </div>\n )\n})\n\nexport default KpiNumber\n"],"names":["getPeriodEndDate","date","granularity","endDate","daysUntilSaturday","currentMonth","quarterEndMonth","isLastPeriodComplete","lastDataPoint","timeDimensionField","timeValue","getQueryGranularity","queryObject","dimensionField","matchingDim","td","filterIncompletePeriod","data","useLastCompletePeriod","skipLastPeriod","noFilter","lastRow","DataHistogram","values","min","max","color","bucketCount","height","formatValue","val","width","showAverageIndicator","targetValue","buckets","range","value","bucketIndex","maxBucketCount","average","sum","averagePosition","targetPosition","jsxs","count","i","normalizedHeight","minHeight","displayHeight","jsx","KpiNumber","React","chartConfig","displayConfig","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","valueRef","getFieldLabel","useCubeFieldLabel","valueFields","useMemo","valueField","sortedData","sorted","a","b","aVal","bVal","filteredData","excludedIncompletePeriod","skippedLastPeriod","dataToUse","row","numericFields","key","avg","acc","formatNumber","useCallback","decimals","prefix","formattedValue","mainValue","showStats","valueColor","colorIndex","targetValues","parseTargetValues","variance","calculateVariance","varianceColor","positiveIndex","negativeIndex","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","measuredWidth","effectiveWidth","timer","resizeObserver","label","Icon","infoCircleIcon","formatVariance"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as r, jsxs as N } from "react/jsx-runtime";
|
|
2
2
|
import K, { useState as M, useRef as T, useEffect as O } from "react";
|
|
3
|
-
import { u as W } from "./charts-core-
|
|
4
|
-
import { D as E } from "./chart-kpi-number-
|
|
3
|
+
import { u as W } from "./charts-core-T8UglYyq.js";
|
|
4
|
+
import { D as E } from "./chart-kpi-number-D62PzKZ1.js";
|
|
5
5
|
const X = K.memo(function({
|
|
6
6
|
data: x,
|
|
7
7
|
chartConfig: l,
|
|
@@ -162,4 +162,4 @@ const X = K.memo(function({
|
|
|
162
162
|
export {
|
|
163
163
|
X as default
|
|
164
164
|
};
|
|
165
|
-
//# sourceMappingURL=chart-kpi-text-
|
|
165
|
+
//# sourceMappingURL=chart-kpi-text-B6Z5tFV1.js.map
|
package/dist/client/chunks/{chart-kpi-text-D0TsUiaO.js.map → chart-kpi-text-B6Z5tFV1.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-kpi-text-D0TsUiaO.js","sources":["../../../src/client/components/charts/KpiText.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport DataHistogram from '../DataHistogram'\nimport type { ChartProps } from '../../types'\n\nconst KpiText = React.memo(function KpiText({ \n data, \n chartConfig, \n displayConfig = {},\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(28)\n const [textWidth, setTextWidth] = useState(0)\n const containerRef = useRef<HTMLDivElement>(null)\n const textRef = useRef<HTMLDivElement>(null)\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const containerWidth = rect.width\n const containerHeight = rect.height\n \n if (containerWidth > 0 && containerHeight > 0) {\n // Calculate font size based on container dimensions\n // For KPI Text displays, text might be longer so use more conservative sizing\n // Also reserve space for potential statistics display\n const widthBasedSize = containerWidth / 8\n const heightBasedSize = containerHeight / 5\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize)\n const clampedFontSize = Math.max(18, Math.min(baseFontSize, 80))\n setFontSize(clampedFontSize)\n }\n }\n \n // Measure the text width after font size is set\n if (textRef.current) {\n const textRect = textRef.current.getBoundingClientRect()\n setTextWidth(textRect.width)\n }\n }\n\n // Initial calculation after a short delay to ensure the container is fully rendered\n const timer = setTimeout(updateDimensions, 100)\n \n const resizeObserver = new ResizeObserver(() => {\n // Debounce the resize updates\n clearTimeout(timer)\n setTimeout(updateDimensions, 50)\n })\n \n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n return () => {\n clearTimeout(timer)\n resizeObserver.disconnect()\n }\n }, [data, chartConfig])\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display</div>\n </div>\n </div>\n )\n }\n\n // Extract value field from chart config - handle both string and array formats\n let valueFields: string[] = []\n if (chartConfig?.yAxis) {\n // Handle both string and array formats\n if (typeof chartConfig.yAxis === 'string') {\n valueFields = [chartConfig.yAxis]\n } else if (Array.isArray(chartConfig.yAxis)) {\n valueFields = chartConfig.yAxis\n }\n }\n \n \n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-danger-bg)',\n color: 'var(--dc-danger)',\n borderColor: 'var(--dc-danger-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure fields configured</div>\n </div>\n </div>\n )\n }\n\n const valueField = valueFields[0] // Use first measure field\n \n // Debug logging (remove in production)\n \n // Extract values for the selected field\n const values = data\n .map(row => {\n // Try direct field access first\n if (row[valueField] !== undefined) {\n return row[valueField]\n }\n \n // If not found, try finding the first available field as fallback\n const availableFields = Object.keys(row)\n if (availableFields.length > 0) {\n // Field not found, using fallback\n return row[availableFields[0]]\n }\n \n return undefined\n })\n .filter(val => val !== null && val !== undefined)\n \n\n if (values.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-warning-bg)',\n color: 'var(--dc-warning)',\n borderColor: 'var(--dc-warning-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No valid data</div>\n <div className=\"dc:text-xs\">All values are null or invalid</div>\n </div>\n </div>\n )\n }\n\n // Calculate statistics for numeric values\n const numericValues = values\n .map(val => Number(val))\n .filter(val => !isNaN(val))\n\n let mainValue: any\n let min: number | null = null\n let max: number | null = null\n let showStats = false\n\n if (numericValues.length > 0) {\n if (values.length === 1) {\n mainValue = values[0]\n } else {\n // Calculate average for multiple numeric values\n const sum = numericValues.reduce((acc, val) => acc + val, 0)\n const avg = sum / numericValues.length\n mainValue = avg\n min = Math.min(...numericValues)\n max = Math.max(...numericValues)\n showStats = true\n }\n } else {\n // Non-numeric values - just use the first one or concatenate if multiple\n mainValue = values.length === 1 ? values[0] : values.join(', ')\n }\n\n // Format number with appropriate units and decimals\n const formatNumber = (value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value)\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return '—'\n }\n\n const decimals = displayConfig.decimals ?? 2\n\n if (Math.abs(value) >= 1e9) {\n return (value / 1e9).toFixed(decimals) + 'B'\n } else if (Math.abs(value) >= 1e6) {\n return (value / 1e6).toFixed(decimals) + 'M'\n } else if (Math.abs(value) >= 1e3) {\n return (value / 1e3).toFixed(decimals) + 'K'\n } else {\n return value.toFixed(decimals)\n }\n }\n\n // Process template string\n const processTemplate = (template: string, value: any): string => {\n try {\n // Create template variables\n const templateVars = {\n value: typeof value === 'number' ? formatNumber(value) : String(value),\n rawValue: value,\n field: valueField,\n fieldLabel: getFieldLabel(valueField),\n min: min !== null ? formatNumber(min) : '',\n max: max !== null ? formatNumber(max) : '',\n count: values.length\n }\n\n // Simple template replacement using ${variable} syntax\n return template.replace(/\\$\\{(\\w+)\\}/g, (match, varName) => {\n if (varName in templateVars) {\n return String(templateVars[varName as keyof typeof templateVars])\n }\n return match\n })\n } catch {\n // Error processing template\n return String(value)\n }\n }\n\n const template = displayConfig.template || '${fieldLabel}: ${value}'\n const displayText = processTemplate(template, mainValue)\n\n // Get color from palette by index, default to first color in palette\n const getValueColor = (): string => {\n if (displayConfig.valueColorIndex !== undefined && colorPalette?.colors) {\n const colorIndex = displayConfig.valueColorIndex\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex]\n }\n }\n // Default to first color in palette if available, otherwise fallback to dark gray\n return colorPalette?.colors?.[0] || '#1f2937'\n }\n\n const valueColor = getValueColor()\n\n return (\n <div \n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{ \n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Main KPI Text */}\n <div \n ref={textRef}\n className=\"dc:font-bold dc:leading-tight dc:text-center\"\n style={{ \n fontSize: `${fontSize}px`,\n color: valueColor \n }}\n >\n {displayText}\n </div>\n\n {/* Data Histogram for multiple values */}\n {showStats && min !== null && max !== null && (\n <div className=\"dc:mt-4\">\n <DataHistogram\n values={values}\n min={min}\n max={max}\n color={valueColor}\n formatValue={formatNumber}\n height={24}\n width={textWidth || 200}\n />\n </div>\n )}\n </div>\n )\n})\n\nexport default KpiText"],"names":["KpiText","React","data","chartConfig","displayConfig","height","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","textRef","getFieldLabel","useCubeFieldLabel","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","textRect","timer","resizeObserver","jsx","jsxs","valueFields","valueField","values","row","availableFields","val","numericValues","mainValue","min","max","showStats","acc","formatNumber","value","decimals","processTemplate","template","templateVars","match","varName","displayText","valueColor","colorIndex","DataHistogram"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-kpi-text-B6Z5tFV1.js","sources":["../../../src/client/components/charts/KpiText.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport DataHistogram from '../DataHistogram'\nimport type { ChartProps } from '../../types'\n\nconst KpiText = React.memo(function KpiText({ \n data, \n chartConfig, \n displayConfig = {},\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(28)\n const [textWidth, setTextWidth] = useState(0)\n const containerRef = useRef<HTMLDivElement>(null)\n const textRef = useRef<HTMLDivElement>(null)\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const containerWidth = rect.width\n const containerHeight = rect.height\n \n if (containerWidth > 0 && containerHeight > 0) {\n // Calculate font size based on container dimensions\n // For KPI Text displays, text might be longer so use more conservative sizing\n // Also reserve space for potential statistics display\n const widthBasedSize = containerWidth / 8\n const heightBasedSize = containerHeight / 5\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize)\n const clampedFontSize = Math.max(18, Math.min(baseFontSize, 80))\n setFontSize(clampedFontSize)\n }\n }\n \n // Measure the text width after font size is set\n if (textRef.current) {\n const textRect = textRef.current.getBoundingClientRect()\n setTextWidth(textRect.width)\n }\n }\n\n // Initial calculation after a short delay to ensure the container is fully rendered\n const timer = setTimeout(updateDimensions, 100)\n \n const resizeObserver = new ResizeObserver(() => {\n // Debounce the resize updates\n clearTimeout(timer)\n setTimeout(updateDimensions, 50)\n })\n \n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n return () => {\n clearTimeout(timer)\n resizeObserver.disconnect()\n }\n }, [data, chartConfig])\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display</div>\n </div>\n </div>\n )\n }\n\n // Extract value field from chart config - handle both string and array formats\n let valueFields: string[] = []\n if (chartConfig?.yAxis) {\n // Handle both string and array formats\n if (typeof chartConfig.yAxis === 'string') {\n valueFields = [chartConfig.yAxis]\n } else if (Array.isArray(chartConfig.yAxis)) {\n valueFields = chartConfig.yAxis\n }\n }\n \n \n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-danger-bg)',\n color: 'var(--dc-danger)',\n borderColor: 'var(--dc-danger-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure fields configured</div>\n </div>\n </div>\n )\n }\n\n const valueField = valueFields[0] // Use first measure field\n \n // Debug logging (remove in production)\n \n // Extract values for the selected field\n const values = data\n .map(row => {\n // Try direct field access first\n if (row[valueField] !== undefined) {\n return row[valueField]\n }\n \n // If not found, try finding the first available field as fallback\n const availableFields = Object.keys(row)\n if (availableFields.length > 0) {\n // Field not found, using fallback\n return row[availableFields[0]]\n }\n \n return undefined\n })\n .filter(val => val !== null && val !== undefined)\n \n\n if (values.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined,\n backgroundColor: 'var(--dc-warning-bg)',\n color: 'var(--dc-warning)',\n borderColor: 'var(--dc-warning-border)'\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No valid data</div>\n <div className=\"dc:text-xs\">All values are null or invalid</div>\n </div>\n </div>\n )\n }\n\n // Calculate statistics for numeric values\n const numericValues = values\n .map(val => Number(val))\n .filter(val => !isNaN(val))\n\n let mainValue: any\n let min: number | null = null\n let max: number | null = null\n let showStats = false\n\n if (numericValues.length > 0) {\n if (values.length === 1) {\n mainValue = values[0]\n } else {\n // Calculate average for multiple numeric values\n const sum = numericValues.reduce((acc, val) => acc + val, 0)\n const avg = sum / numericValues.length\n mainValue = avg\n min = Math.min(...numericValues)\n max = Math.max(...numericValues)\n showStats = true\n }\n } else {\n // Non-numeric values - just use the first one or concatenate if multiple\n mainValue = values.length === 1 ? values[0] : values.join(', ')\n }\n\n // Format number with appropriate units and decimals\n const formatNumber = (value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value)\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return '—'\n }\n\n const decimals = displayConfig.decimals ?? 2\n\n if (Math.abs(value) >= 1e9) {\n return (value / 1e9).toFixed(decimals) + 'B'\n } else if (Math.abs(value) >= 1e6) {\n return (value / 1e6).toFixed(decimals) + 'M'\n } else if (Math.abs(value) >= 1e3) {\n return (value / 1e3).toFixed(decimals) + 'K'\n } else {\n return value.toFixed(decimals)\n }\n }\n\n // Process template string\n const processTemplate = (template: string, value: any): string => {\n try {\n // Create template variables\n const templateVars = {\n value: typeof value === 'number' ? formatNumber(value) : String(value),\n rawValue: value,\n field: valueField,\n fieldLabel: getFieldLabel(valueField),\n min: min !== null ? formatNumber(min) : '',\n max: max !== null ? formatNumber(max) : '',\n count: values.length\n }\n\n // Simple template replacement using ${variable} syntax\n return template.replace(/\\$\\{(\\w+)\\}/g, (match, varName) => {\n if (varName in templateVars) {\n return String(templateVars[varName as keyof typeof templateVars])\n }\n return match\n })\n } catch {\n // Error processing template\n return String(value)\n }\n }\n\n const template = displayConfig.template || '${fieldLabel}: ${value}'\n const displayText = processTemplate(template, mainValue)\n\n // Get color from palette by index, default to first color in palette\n const getValueColor = (): string => {\n if (displayConfig.valueColorIndex !== undefined && colorPalette?.colors) {\n const colorIndex = displayConfig.valueColorIndex\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex]\n }\n }\n // Default to first color in palette if available, otherwise fallback to dark gray\n return colorPalette?.colors?.[0] || '#1f2937'\n }\n\n const valueColor = getValueColor()\n\n return (\n <div \n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{ \n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? '200px' : undefined\n }}\n >\n {/* Main KPI Text */}\n <div \n ref={textRef}\n className=\"dc:font-bold dc:leading-tight dc:text-center\"\n style={{ \n fontSize: `${fontSize}px`,\n color: valueColor \n }}\n >\n {displayText}\n </div>\n\n {/* Data Histogram for multiple values */}\n {showStats && min !== null && max !== null && (\n <div className=\"dc:mt-4\">\n <DataHistogram\n values={values}\n min={min}\n max={max}\n color={valueColor}\n formatValue={formatNumber}\n height={24}\n width={textWidth || 200}\n />\n </div>\n )}\n </div>\n )\n})\n\nexport default KpiText"],"names":["KpiText","React","data","chartConfig","displayConfig","height","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","textRef","getFieldLabel","useCubeFieldLabel","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","textRect","timer","resizeObserver","jsx","jsxs","valueFields","valueField","values","row","availableFields","val","numericValues","mainValue","min","max","showStats","acc","formatNumber","value","decimals","processTemplate","template","templateVars","match","varName","displayText","valueColor","colorIndex","DataHistogram"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as o, jsxs as S, Fragment as le } from "react/jsx-runtime";
|
|
2
2
|
import de, { useState as fe, useMemo as E } from "react";
|
|
3
3
|
import { LineChart as ue, CartesianGrid as me, XAxis as xe, YAxis as B, Legend as he, Line as z } from "recharts";
|
|
4
|
-
import { u as ye, t as pe, C as ge, p as _e, s as Ae, a as ve, g as q, d as J, f as M, b as Ne, c as Q } from "./charts-core-
|
|
5
|
-
import { A as we } from "./chart-bar-
|
|
4
|
+
import { u as ye, t as pe, C as ge, p as _e, s as Ae, a as ve, g as q, d as J, f as M, b as Ne, c as Q } from "./charts-core-T8UglYyq.js";
|
|
5
|
+
import { A as we } from "./chart-bar-DBI41w05.js";
|
|
6
6
|
function $(t) {
|
|
7
7
|
return t.length > 0 && "__periodIndex" in t[0];
|
|
8
8
|
}
|
|
@@ -447,4 +447,4 @@ export {
|
|
|
447
447
|
$ as i,
|
|
448
448
|
Re as t
|
|
449
449
|
};
|
|
450
|
-
//# sourceMappingURL=chart-line-
|
|
450
|
+
//# sourceMappingURL=chart-line-Ds4BYA0K.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-line-C7VStgaJ.js","sources":["../../../src/client/utils/comparisonUtils.ts","../../../src/client/components/charts/LineChart.tsx"],"sourcesContent":["/**\n * Comparison Data Utilities\n * Handles period-over-period comparison data transformation for charts\n *\n * These utilities detect comparison query results (with __periodIndex metadata)\n * and transform them for visualization in either 'separate' or 'overlay' mode.\n */\n\n/**\n * Check if data contains comparison period metadata\n */\nexport function isComparisonData(data: any[]): boolean {\n return data.length > 0 && '__periodIndex' in data[0]\n}\n\n/**\n * Get unique period labels from comparison data\n */\nexport function getPeriodLabels(data: any[]): string[] {\n if (!isComparisonData(data)) return []\n\n const labels = new Set<string>()\n for (const row of data) {\n if (row.__period) {\n labels.add(row.__period)\n }\n }\n return Array.from(labels)\n}\n\n/**\n * Get period indices from comparison data\n */\nexport function getPeriodIndices(data: any[]): number[] {\n if (!isComparisonData(data)) return []\n\n const indices = new Set<number>()\n for (const row of data) {\n if (typeof row.__periodIndex === 'number') {\n indices.add(row.__periodIndex)\n }\n }\n return Array.from(indices).sort((a, b) => a - b)\n}\n\n/**\n * Generate a short label for a period (used in legends)\n * Uses simple \"Current\" / \"Prior\" labels for clarity\n */\nexport function generatePeriodShortLabel(_periodLabel: string, index: number): string {\n return index === 0 ? 'Current' : 'Prior'\n}\n\n/**\n * Transform comparison data for 'separate' mode\n * Returns data with each row having its original measure values\n * Series are created per period (e.g., \"totalLinesOfCode (Current)\", \"totalLinesOfCode (Prior)\")\n */\nexport function transformForSeparateMode(\n data: any[],\n measures: string[],\n _timeDimensionKey: string\n): { data: any[], seriesKeys: string[] } {\n if (!isComparisonData(data)) {\n return { data, seriesKeys: measures }\n }\n\n const periodLabels = getPeriodLabels(data)\n const seriesKeys: string[] = []\n\n // Create series key for each measure + period combination\n for (const measure of measures) {\n for (let i = 0; i < periodLabels.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i], i)\n const key = `${measure} (${shortLabel})`\n seriesKeys.push(key)\n }\n }\n\n // Data already has period info, just return as-is for separate mode\n // The chart will group by time dimension and show multiple lines\n return { data, seriesKeys }\n}\n\n/**\n * Detect dimension fields in comparison data\n * Returns fields that are not measures, time dimension, or metadata fields\n */\nfunction detectDimensionFields(\n data: any[],\n measures: string[],\n timeDimensionKey: string\n): string[] {\n if (data.length === 0) return []\n\n const metadataFields = ['__period', '__periodIndex', '__periodDayIndex']\n const firstRow = data[0]\n const dimensions: string[] = []\n\n for (const key of Object.keys(firstRow)) {\n if (\n !measures.includes(key) &&\n key !== timeDimensionKey &&\n !metadataFields.includes(key)\n ) {\n dimensions.push(key)\n }\n }\n\n return dimensions\n}\n\n/**\n * Get unique dimension values from data for a set of dimension fields\n */\nfunction getUniqueDimensionValues(\n data: any[],\n dimensionFields: string[]\n): Map<string, Set<any>> {\n const values = new Map<string, Set<any>>()\n\n for (const field of dimensionFields) {\n values.set(field, new Set())\n }\n\n for (const row of data) {\n for (const field of dimensionFields) {\n if (row[field] !== undefined && row[field] !== null) {\n values.get(field)!.add(row[field])\n }\n }\n }\n\n return values\n}\n\n/**\n * Transform comparison data for 'overlay' mode\n * Pivots data so each row represents a day-of-period index,\n * with separate columns for each period's values.\n *\n * When dimensions are present, creates series keys that include\n * dimension values: \"Engineering - Total Lines of Code (Current)\"\n *\n * Input (without dimensions):\n * [\n * { date: '2024-01-01', value: 100, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2024-01-02', value: 110, __periodIndex: 0, __periodDayIndex: 1 },\n * { date: '2023-01-01', value: 80, __periodIndex: 1, __periodDayIndex: 0 },\n * { date: '2023-01-02', value: 85, __periodIndex: 1, __periodDayIndex: 1 },\n * ]\n *\n * Output (without dimensions):\n * [\n * { __periodDayIndex: 0, 'value (Current)': 100, 'value (Prior)': 80 },\n * { __periodDayIndex: 1, 'value (Current)': 110, 'value (Prior)': 85 },\n * ]\n *\n * Input (with dimensions):\n * [\n * { date: '2024-01-01', 'Dept.name': 'Engineering', value: 100, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2024-01-01', 'Dept.name': 'Sales', value: 50, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2023-01-01', 'Dept.name': 'Engineering', value: 80, __periodIndex: 1, __periodDayIndex: 0 },\n * { date: '2023-01-01', 'Dept.name': 'Sales', value: 40, __periodIndex: 1, __periodDayIndex: 0 },\n * ]\n *\n * Output (with dimensions):\n * [\n * {\n * __periodDayIndex: 0,\n * 'Engineering - value (Current)': 100,\n * 'Engineering - value (Prior)': 80,\n * 'Sales - value (Current)': 50,\n * 'Sales - value (Prior)': 40,\n * },\n * ]\n */\nexport function transformForOverlayMode(\n data: any[],\n measures: string[],\n timeDimensionKey: string,\n getFieldLabel?: (fieldName: string) => string\n): { data: any[], seriesKeys: string[], xAxisKey: string } {\n if (!isComparisonData(data)) {\n return { data, seriesKeys: measures, xAxisKey: timeDimensionKey }\n }\n\n const periodLabels = getPeriodLabels(data)\n const periodIndices = getPeriodIndices(data)\n\n // Detect dimension fields in the data\n const dimensionFields = detectDimensionFields(data, measures, timeDimensionKey)\n const hasDimensions = dimensionFields.length > 0\n\n // Get unique dimension values for generating series keys\n const uniqueDimensionValues = hasDimensions\n ? getUniqueDimensionValues(data, dimensionFields)\n : null\n\n // Group data by __periodDayIndex\n const groupedByDayIndex = new Map<number, Record<string, any>>()\n\n for (const row of data) {\n const dayIndex = row.__periodDayIndex\n const periodIndex = row.__periodIndex\n\n if (!groupedByDayIndex.has(dayIndex)) {\n groupedByDayIndex.set(dayIndex, {\n __periodDayIndex: dayIndex,\n // Store the date from the first period (index 0) for reference\n __displayDate: periodIndex === 0 ? row[timeDimensionKey] : undefined\n })\n }\n\n const groupedRow = groupedByDayIndex.get(dayIndex)!\n\n // If this is the first period and we don't have a display date yet, add it\n if (!groupedRow.__displayDate && row[timeDimensionKey]) {\n groupedRow.__displayDate = row[timeDimensionKey]\n }\n\n // Build dimension prefix if dimensions are present\n let dimensionPrefix = ''\n if (hasDimensions) {\n const dimensionValues = dimensionFields.map(field => {\n const value = row[field]\n return getFieldLabel ? getFieldLabel(String(value)) : String(value)\n })\n dimensionPrefix = dimensionValues.join(' / ')\n }\n\n // Add measure values with optional dimension prefix and period suffix\n const shortLabel = generatePeriodShortLabel(periodLabels[periodIndex] || '', periodIndex)\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n const key = dimensionPrefix\n ? `${dimensionPrefix} - ${displayName} (${shortLabel})`\n : `${displayName} (${shortLabel})`\n groupedRow[key] = row[measure]\n }\n }\n\n // Convert to array and sort by day index\n const transformedData = Array.from(groupedByDayIndex.values())\n .sort((a, b) => a.__periodDayIndex - b.__periodDayIndex)\n\n // Generate series keys (using display names to match the data keys)\n const seriesKeys: string[] = []\n\n if (hasDimensions && uniqueDimensionValues) {\n // Generate all combinations of dimension values\n const dimensionCombinations = generateDimensionCombinations(\n dimensionFields,\n uniqueDimensionValues,\n getFieldLabel\n )\n\n // For each dimension combination, create series keys for each measure + period\n for (const dimCombo of dimensionCombinations) {\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n for (let i = 0; i < periodIndices.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i] || '', i)\n seriesKeys.push(`${dimCombo} - ${displayName} (${shortLabel})`)\n }\n }\n }\n } else {\n // No dimensions - generate simple measure + period keys\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n for (let i = 0; i < periodIndices.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i] || '', i)\n seriesKeys.push(`${displayName} (${shortLabel})`)\n }\n }\n }\n\n return {\n data: transformedData,\n seriesKeys,\n xAxisKey: '__periodDayIndex'\n }\n}\n\n/**\n * Generate all combinations of dimension values as formatted strings\n */\nfunction generateDimensionCombinations(\n dimensionFields: string[],\n uniqueValues: Map<string, Set<any>>,\n getFieldLabel?: (fieldName: string) => string\n): string[] {\n if (dimensionFields.length === 0) return []\n\n // For single dimension, just return the values\n if (dimensionFields.length === 1) {\n const field = dimensionFields[0]\n const values = Array.from(uniqueValues.get(field) || [])\n return values.map(v => getFieldLabel ? getFieldLabel(String(v)) : String(v))\n }\n\n // For multiple dimensions, generate cartesian product\n const result: string[] = []\n const fieldValues = dimensionFields.map(field =>\n Array.from(uniqueValues.get(field) || [])\n )\n\n function generateCombos(index: number, current: string[]): void {\n if (index === fieldValues.length) {\n const formatted = current.map(v =>\n getFieldLabel ? getFieldLabel(String(v)) : String(v)\n )\n result.push(formatted.join(' / '))\n return\n }\n\n for (const value of fieldValues[index]) {\n generateCombos(index + 1, [...current, value])\n }\n }\n\n generateCombos(0, [])\n return result\n}\n\n/**\n * Format the period day index for display on X-axis\n * Can show as \"Day 1\", \"Day 2\", etc., or as the original date\n */\nexport function formatPeriodDayIndex(\n dayIndex: number,\n displayDate?: string | Date,\n options?: {\n showDayNumber?: boolean\n dateFormat?: 'short' | 'long'\n }\n): string {\n if (options?.showDayNumber) {\n return `Day ${dayIndex + 1}`\n }\n\n if (displayDate) {\n const date = typeof displayDate === 'string' ? new Date(displayDate) : displayDate\n if (!isNaN(date.getTime())) {\n return date.toLocaleDateString('en-US', {\n month: options?.dateFormat === 'long' ? 'long' : 'short',\n day: 'numeric'\n })\n }\n }\n\n return `${dayIndex + 1}`\n}\n\n/**\n * Check if a series key represents a prior period (not the first period)\n * Used for applying different styling to prior period lines\n */\nexport function isPriorPeriodSeries(seriesKey: string, periodLabels: string[]): boolean {\n if (periodLabels.length < 2) return false\n\n // Check if the series key contains any label other than the first period's\n for (let i = 1; i < periodLabels.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i], i)\n if (seriesKey.includes(`(${shortLabel})`)) {\n return true\n }\n }\n\n // Also check for \"(Prior\" pattern\n return seriesKey.includes('(Prior')\n}\n\n/**\n * Get the stroke dash array for prior period styling\n */\nexport function getPriorPeriodStrokeDashArray(\n style: 'solid' | 'dashed' | 'dotted' = 'dashed'\n): string | undefined {\n switch (style) {\n case 'solid':\n return undefined\n case 'dashed':\n return '5 5'\n case 'dotted':\n return '2 2'\n default:\n return '5 5'\n }\n}\n","import React, { useState, useMemo } from 'react'\nimport { LineChart as RechartsLineChart, Line, XAxis, YAxis, CartesianGrid, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport AngledXAxisTick from './AngledXAxisTick'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatAxisValue, formatTimeValue, getFieldGranularity } from '../../utils/chartUtils'\nimport { parseTargetValues, spreadTargetValues } from '../../utils/targetUtils'\nimport {\n isComparisonData,\n getPeriodLabels,\n transformForOverlayMode,\n isPriorPeriodSeries,\n getPriorPeriodStrokeDashArray\n} from '../../utils/comparisonUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst LineChart = React.memo(function LineChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\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 // Extract Y-axis fields early for use in useMemo hooks\n // This ensures hooks are always called in the same order\n const yAxisFields = useMemo(() => {\n if (chartConfig?.yAxis) {\n return Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis]\n }\n if (chartConfig?.y) {\n return Array.isArray(chartConfig.y) ? chartConfig.y : [chartConfig.y]\n }\n return []\n }, [chartConfig?.yAxis, chartConfig?.y])\n\n // Dual Y-axis support: extract yAxisAssignment from chartConfig (memoized to prevent object recreation)\n // MUST be called before any early returns to satisfy React hooks rules\n const yAxisAssignment = useMemo(() =>\n chartConfig?.yAxisAssignment || {},\n [chartConfig?.yAxisAssignment]\n )\n\n // Build mapping from series key (label) to original field name (memoized to prevent object recreation)\n // This is needed because seriesKeys use display labels, not field names\n // MUST be called before any early returns to satisfy React hooks rules\n const seriesKeyToField = useMemo(() => {\n const mapping: Record<string, string> = {}\n yAxisFields.forEach((field) => {\n const label = getFieldLabel(field)\n mapping[label] = field\n })\n return mapping\n }, [yAxisFields, getFieldLabel])\n\n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n connectNulls: displayConfig?.connectNulls ?? false\n }\n\n // Extract axis format configs\n const leftYAxisFormat = displayConfig?.leftYAxisFormat\n const rightYAxisFormat = displayConfig?.rightYAxisFormat\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\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display in line chart</div>\n </div>\n </div>\n )\n }\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: 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 seriesFields = chartConfig.series || []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format\n xAxisField = chartConfig.x\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\">Configuration Error</div>\n <div className=\"dc:text-xs\">Invalid or missing chart axis configuration</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || 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\">Configuration Error</div>\n <div className=\"dc:text-xs\">Missing required X-axis or Y-axis fields</div>\n </div>\n </div>\n )\n }\n\n // Check if this is comparison data (has __periodIndex metadata)\n const hasComparisonData = isComparisonData(data)\n const priorPeriodStyle = displayConfig?.priorPeriodStyle || 'dashed'\n const priorPeriodOpacity = displayConfig?.priorPeriodOpacity ?? 0.5\n const periodLabels = hasComparisonData ? getPeriodLabels(data) : []\n\n // Transform data based on comparison mode\n let chartData: any[]\n let seriesKeys: string[]\n let effectiveXAxisKey = 'name' // Default X-axis key after transformation\n\n if (hasComparisonData) {\n // For comparison data, always use overlay transformation to align by period day index\n // Both 'separate' and 'overlay' modes use the same data transformation,\n // they differ only in styling (dashed lines, opacity for prior periods in overlay mode)\n const overlayResult = transformForOverlayMode(data, yAxisFields, xAxisField, getFieldLabel)\n chartData = overlayResult.data\n seriesKeys = overlayResult.seriesKeys\n effectiveXAxisKey = '__periodDayIndex'\n } else {\n // Standard mode: use normal transformation\n const standardResult = transformChartDataWithSeries(\n data,\n xAxisField,\n yAxisFields,\n queryObject,\n seriesFields,\n getFieldLabel\n )\n chartData = standardResult.data\n seriesKeys = standardResult.seriesKeys\n }\n\n // Helper to find field from series key, handling comparison suffixes like \"(Current)\" and \"(Prior)\"\n const findFieldFromSeriesKey = (seriesKey: string): string | undefined => {\n // Direct match first\n if (seriesKeyToField[seriesKey]) {\n return seriesKeyToField[seriesKey]\n }\n // For comparison data, strip the period suffix and any dimension prefix\n // Series keys look like: \"Label (Current)\", \"Label (Prior)\", or \"DimValue - Label (Current)\"\n const withoutSuffix = seriesKey.replace(/\\s*\\((Current|Prior)\\)$/, '')\n // Check if it has a dimension prefix (contains \" - \")\n const parts = withoutSuffix.split(' - ')\n const measureLabel = parts[parts.length - 1] // Last part is the measure label\n return seriesKeyToField[measureLabel]\n }\n\n // Determine if we need a right Y-axis\n const hasRightAxis = yAxisFields.some((field) => yAxisAssignment[field] === 'right')\n\n // Get fields for left and right axes for labels\n const leftAxisFields = yAxisFields.filter((f) => (yAxisAssignment[f] || 'left') === 'left')\n const rightAxisFields = yAxisFields.filter((f) => yAxisAssignment[f] === 'right')\n\n // Determine if legend will be shown\n const showLegend = safeDisplayConfig.showLegend\n\n // Use custom chart margins with extra space for Y-axis labels\n const chartMargins = {\n ...CHART_MARGINS,\n left: 40, // Space for left Y-axis label\n right: hasRightAxis ? 40 : 20 // Extra space for right Y-axis label if needed\n }\n\n // Process target values and add to chart data\n const targetValues = parseTargetValues(displayConfig?.target || '')\n const spreadTargets = spreadTargetValues(targetValues, chartData.length)\n\n // Add target data to chart data if targets exist\n let enhancedChartData = chartData\n if (spreadTargets.length > 0) {\n enhancedChartData = chartData.map((dataPoint, index) => ({\n ...dataPoint,\n __target: spreadTargets[index] || null\n }))\n }\n\n // Validate transformed data\n if (!chartData || chartData.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\">No valid data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for line chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsLineChart data={enhancedChartData} margin={chartMargins} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <CartesianGrid strokeDasharray=\"3 3\" style={{ pointerEvents: 'none' }} />\n )}\n <XAxis\n dataKey={effectiveXAxisKey}\n type=\"category\"\n tick={<AngledXAxisTick tickFormatter={\n hasComparisonData\n ? (value: string | number, index: number) => {\n // For comparison data, show the date from the current period\n // formatted according to the query's granularity\n const row = chartData[index]\n if (row?.__displayDate) {\n const granularity = getFieldGranularity(queryObject, xAxisField)\n return formatTimeValue(row.__displayDate, granularity)\n }\n return `Period ${Number(value) + 1}`\n }\n : undefined\n } />}\n height={60}\n />\n <YAxis\n yAxisId=\"left\"\n orientation=\"left\"\n tick={{ fontSize: 12 }}\n tickFormatter={leftYAxisFormat ? (value) => formatAxisValue(value, leftYAxisFormat) : undefined}\n label={\n leftAxisFields.length > 0\n ? {\n value: leftYAxisFormat?.label || getFieldLabel(leftAxisFields[0]),\n angle: -90,\n position: 'left',\n style: { textAnchor: 'middle', fontSize: '12px' }\n }\n : undefined\n }\n />\n {hasRightAxis && (\n <YAxis\n yAxisId=\"right\"\n orientation=\"right\"\n tick={{ fontSize: 12 }}\n tickFormatter={rightYAxisFormat ? (value) => formatAxisValue(value, rightYAxisFormat) : undefined}\n label={\n rightAxisFields.length > 0\n ? {\n value: rightYAxisFormat?.label || getFieldLabel(rightAxisFields[0]),\n angle: 90,\n position: 'right',\n style: { textAnchor: 'middle', fontSize: '12px' }\n }\n : undefined\n }\n />\n )}\n {safeDisplayConfig.showTooltip && (\n <ChartTooltip\n formatter={(value: any, name: any) => {\n // Handle null values in tooltip\n if (value === null || value === undefined) {\n return ['No data', name]\n }\n if (name === 'Target') {\n // Use left Y-axis format for target values\n return [formatAxisValue(value, leftYAxisFormat), 'Target Value']\n }\n\n // Determine which axis format to use based on series name\n const originalField = findFieldFromSeriesKey(name)\n const axisId = originalField && yAxisAssignment[originalField] === 'right' ? 'right' : 'left'\n const formatConfig = axisId === 'right' ? rightYAxisFormat : leftYAxisFormat\n // Series name is already formatted (e.g., \"Total Lines of Code (Current)\")\n return [formatAxisValue(value, formatConfig), name]\n }}\n labelFormatter={\n hasComparisonData\n ? (label: any, payload: any) => {\n // For comparison data, show the date from the current period\n // formatted according to the query's granularity\n if (payload && payload.length > 0) {\n const row = payload[0]?.payload\n if (row?.__displayDate) {\n const granularity = getFieldGranularity(queryObject, xAxisField)\n return formatTimeValue(row.__displayDate, granularity)\n }\n }\n return `Period ${Number(label) + 1}`\n }\n : undefined\n }\n />\n )}\n {showLegend && (\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '25px' }}\n iconType=\"line\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {seriesKeys.map((seriesKey, index) => {\n // Look up the original field name to get its axis assignment\n const originalField = findFieldFromSeriesKey(seriesKey)\n const axisId = originalField && yAxisAssignment[originalField] === 'right' ? 'right' : 'left'\n\n // Determine if this is a prior period series (for styling)\n const isPriorPeriod = hasComparisonData && isPriorPeriodSeries(seriesKey, periodLabels)\n const strokeDashArray = isPriorPeriod ? getPriorPeriodStrokeDashArray(priorPeriodStyle) : undefined\n const opacity = isPriorPeriod ? priorPeriodOpacity : 1\n\n // When drill is enabled, show persistent dots for better click targets\n const lineColor = (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n\n return (\n <Line\n key={seriesKey}\n type=\"monotone\"\n dataKey={seriesKey}\n yAxisId={axisId}\n stroke={lineColor}\n strokeWidth={isPriorPeriod ? 1.5 : 2}\n strokeDasharray={strokeDashArray}\n dot={isPriorPeriod ? false : (props: any) => {\n const { cx, cy, payload, key } = props\n if (cx === undefined || cy === undefined) return null\n\n const handleClick = (event: React.MouseEvent) => {\n event.stopPropagation()\n event.preventDefault()\n if (onDataPointClick) {\n onDataPointClick({\n dataPoint: payload,\n clickedField: originalField || seriesKey,\n xValue: payload.name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }\n\n // When drill is enabled, render clickable dots with background to mask grid\n if (drillEnabled && onDataPointClick) {\n return (\n <g key={key}>\n {/* Background to mask grid lines - uses theme surface color */}\n <circle\n cx={cx}\n cy={cy}\n r={6}\n fill=\"var(--dc-surface)\"\n style={{ pointerEvents: 'none' }}\n />\n {/* Visible dot with click handler */}\n <circle\n cx={cx}\n cy={cy}\n r={4}\n fill=\"var(--dc-surface)\"\n stroke={lineColor}\n strokeWidth={2}\n cursor=\"pointer\"\n onClick={(e: React.MouseEvent<SVGCircleElement>) => {\n handleClick(e as unknown as React.MouseEvent)\n }}\n />\n </g>\n )\n }\n\n // Non-drill mode: simple small dot\n return (\n <circle\n key={key}\n cx={cx}\n cy={cy}\n r={3}\n fill={lineColor}\n />\n )\n }}\n activeDot={false}\n strokeOpacity={\n hoveredLegend\n ? (hoveredLegend === seriesKey ? 1 : 0.3)\n : opacity\n }\n connectNulls={safeDisplayConfig.connectNulls}\n />\n )\n })}\n {spreadTargets.length > 0 && (\n <>\n {/* White background line */}\n <Line\n type=\"monotone\"\n dataKey=\"__target\"\n yAxisId=\"left\"\n stroke=\"#ffffff\"\n strokeWidth={2}\n dot={false}\n activeDot={false}\n connectNulls={false}\n />\n {/* Grey dashed line on top */}\n <Line\n type=\"monotone\"\n dataKey=\"__target\"\n yAxisId=\"left\"\n name=\"Target\"\n stroke=\"#8B5CF6\"\n strokeWidth={2}\n strokeDasharray=\"2 3\"\n dot={false}\n activeDot={false}\n connectNulls={false}\n />\n </>\n )}\n </RechartsLineChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'LineChart 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\">Line Chart Error</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : 'Unknown rendering error'}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">Check the data and configuration</div>\n </div>\n </div>\n )\n }\n})\n\nexport default LineChart\n"],"names":["isComparisonData","data","getPeriodLabels","labels","row","getPeriodIndices","indices","a","b","generatePeriodShortLabel","_periodLabel","index","transformForSeparateMode","measures","_timeDimensionKey","periodLabels","seriesKeys","measure","shortLabel","key","detectDimensionFields","timeDimensionKey","metadataFields","firstRow","dimensions","getUniqueDimensionValues","dimensionFields","values","field","transformForOverlayMode","getFieldLabel","periodIndices","hasDimensions","uniqueDimensionValues","groupedByDayIndex","dayIndex","periodIndex","groupedRow","dimensionPrefix","value","displayName","transformedData","dimensionCombinations","generateDimensionCombinations","dimCombo","i","uniqueValues","v","result","fieldValues","generateCombos","current","formatted","formatPeriodDayIndex","displayDate","options","date","isPriorPeriodSeries","seriesKey","getPriorPeriodStrokeDashArray","style","LineChart","React","chartConfig","displayConfig","queryObject","height","colorPalette","onDataPointClick","drillEnabled","hoveredLegend","setHoveredLegend","useState","useCubeFieldLabel","yAxisFields","useMemo","yAxisAssignment","seriesKeyToField","mapping","label","safeDisplayConfig","leftYAxisFormat","rightYAxisFormat","jsx","jsxs","xAxisField","seriesFields","hasComparisonData","priorPeriodStyle","priorPeriodOpacity","chartData","effectiveXAxisKey","overlayResult","standardResult","transformChartDataWithSeries","findFieldFromSeriesKey","parts","measureLabel","hasRightAxis","leftAxisFields","f","rightAxisFields","showLegend","chartMargins","CHART_MARGINS","targetValues","parseTargetValues","spreadTargets","spreadTargetValues","enhancedChartData","dataPoint","ChartContainer","RechartsLineChart","CartesianGrid","XAxis","AngledXAxisTick","granularity","getFieldGranularity","formatTimeValue","YAxis","formatAxisValue","ChartTooltip","name","originalField","formatConfig","payload","Legend","o","axisId","isPriorPeriod","strokeDashArray","opacity","lineColor","CHART_COLORS","Line","props","cx","cy","handleClick","event","e","Fragment","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-line-Ds4BYA0K.js","sources":["../../../src/client/utils/comparisonUtils.ts","../../../src/client/components/charts/LineChart.tsx"],"sourcesContent":["/**\n * Comparison Data Utilities\n * Handles period-over-period comparison data transformation for charts\n *\n * These utilities detect comparison query results (with __periodIndex metadata)\n * and transform them for visualization in either 'separate' or 'overlay' mode.\n */\n\n/**\n * Check if data contains comparison period metadata\n */\nexport function isComparisonData(data: any[]): boolean {\n return data.length > 0 && '__periodIndex' in data[0]\n}\n\n/**\n * Get unique period labels from comparison data\n */\nexport function getPeriodLabels(data: any[]): string[] {\n if (!isComparisonData(data)) return []\n\n const labels = new Set<string>()\n for (const row of data) {\n if (row.__period) {\n labels.add(row.__period)\n }\n }\n return Array.from(labels)\n}\n\n/**\n * Get period indices from comparison data\n */\nexport function getPeriodIndices(data: any[]): number[] {\n if (!isComparisonData(data)) return []\n\n const indices = new Set<number>()\n for (const row of data) {\n if (typeof row.__periodIndex === 'number') {\n indices.add(row.__periodIndex)\n }\n }\n return Array.from(indices).sort((a, b) => a - b)\n}\n\n/**\n * Generate a short label for a period (used in legends)\n * Uses simple \"Current\" / \"Prior\" labels for clarity\n */\nexport function generatePeriodShortLabel(_periodLabel: string, index: number): string {\n return index === 0 ? 'Current' : 'Prior'\n}\n\n/**\n * Transform comparison data for 'separate' mode\n * Returns data with each row having its original measure values\n * Series are created per period (e.g., \"totalLinesOfCode (Current)\", \"totalLinesOfCode (Prior)\")\n */\nexport function transformForSeparateMode(\n data: any[],\n measures: string[],\n _timeDimensionKey: string\n): { data: any[], seriesKeys: string[] } {\n if (!isComparisonData(data)) {\n return { data, seriesKeys: measures }\n }\n\n const periodLabels = getPeriodLabels(data)\n const seriesKeys: string[] = []\n\n // Create series key for each measure + period combination\n for (const measure of measures) {\n for (let i = 0; i < periodLabels.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i], i)\n const key = `${measure} (${shortLabel})`\n seriesKeys.push(key)\n }\n }\n\n // Data already has period info, just return as-is for separate mode\n // The chart will group by time dimension and show multiple lines\n return { data, seriesKeys }\n}\n\n/**\n * Detect dimension fields in comparison data\n * Returns fields that are not measures, time dimension, or metadata fields\n */\nfunction detectDimensionFields(\n data: any[],\n measures: string[],\n timeDimensionKey: string\n): string[] {\n if (data.length === 0) return []\n\n const metadataFields = ['__period', '__periodIndex', '__periodDayIndex']\n const firstRow = data[0]\n const dimensions: string[] = []\n\n for (const key of Object.keys(firstRow)) {\n if (\n !measures.includes(key) &&\n key !== timeDimensionKey &&\n !metadataFields.includes(key)\n ) {\n dimensions.push(key)\n }\n }\n\n return dimensions\n}\n\n/**\n * Get unique dimension values from data for a set of dimension fields\n */\nfunction getUniqueDimensionValues(\n data: any[],\n dimensionFields: string[]\n): Map<string, Set<any>> {\n const values = new Map<string, Set<any>>()\n\n for (const field of dimensionFields) {\n values.set(field, new Set())\n }\n\n for (const row of data) {\n for (const field of dimensionFields) {\n if (row[field] !== undefined && row[field] !== null) {\n values.get(field)!.add(row[field])\n }\n }\n }\n\n return values\n}\n\n/**\n * Transform comparison data for 'overlay' mode\n * Pivots data so each row represents a day-of-period index,\n * with separate columns for each period's values.\n *\n * When dimensions are present, creates series keys that include\n * dimension values: \"Engineering - Total Lines of Code (Current)\"\n *\n * Input (without dimensions):\n * [\n * { date: '2024-01-01', value: 100, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2024-01-02', value: 110, __periodIndex: 0, __periodDayIndex: 1 },\n * { date: '2023-01-01', value: 80, __periodIndex: 1, __periodDayIndex: 0 },\n * { date: '2023-01-02', value: 85, __periodIndex: 1, __periodDayIndex: 1 },\n * ]\n *\n * Output (without dimensions):\n * [\n * { __periodDayIndex: 0, 'value (Current)': 100, 'value (Prior)': 80 },\n * { __periodDayIndex: 1, 'value (Current)': 110, 'value (Prior)': 85 },\n * ]\n *\n * Input (with dimensions):\n * [\n * { date: '2024-01-01', 'Dept.name': 'Engineering', value: 100, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2024-01-01', 'Dept.name': 'Sales', value: 50, __periodIndex: 0, __periodDayIndex: 0 },\n * { date: '2023-01-01', 'Dept.name': 'Engineering', value: 80, __periodIndex: 1, __periodDayIndex: 0 },\n * { date: '2023-01-01', 'Dept.name': 'Sales', value: 40, __periodIndex: 1, __periodDayIndex: 0 },\n * ]\n *\n * Output (with dimensions):\n * [\n * {\n * __periodDayIndex: 0,\n * 'Engineering - value (Current)': 100,\n * 'Engineering - value (Prior)': 80,\n * 'Sales - value (Current)': 50,\n * 'Sales - value (Prior)': 40,\n * },\n * ]\n */\nexport function transformForOverlayMode(\n data: any[],\n measures: string[],\n timeDimensionKey: string,\n getFieldLabel?: (fieldName: string) => string\n): { data: any[], seriesKeys: string[], xAxisKey: string } {\n if (!isComparisonData(data)) {\n return { data, seriesKeys: measures, xAxisKey: timeDimensionKey }\n }\n\n const periodLabels = getPeriodLabels(data)\n const periodIndices = getPeriodIndices(data)\n\n // Detect dimension fields in the data\n const dimensionFields = detectDimensionFields(data, measures, timeDimensionKey)\n const hasDimensions = dimensionFields.length > 0\n\n // Get unique dimension values for generating series keys\n const uniqueDimensionValues = hasDimensions\n ? getUniqueDimensionValues(data, dimensionFields)\n : null\n\n // Group data by __periodDayIndex\n const groupedByDayIndex = new Map<number, Record<string, any>>()\n\n for (const row of data) {\n const dayIndex = row.__periodDayIndex\n const periodIndex = row.__periodIndex\n\n if (!groupedByDayIndex.has(dayIndex)) {\n groupedByDayIndex.set(dayIndex, {\n __periodDayIndex: dayIndex,\n // Store the date from the first period (index 0) for reference\n __displayDate: periodIndex === 0 ? row[timeDimensionKey] : undefined\n })\n }\n\n const groupedRow = groupedByDayIndex.get(dayIndex)!\n\n // If this is the first period and we don't have a display date yet, add it\n if (!groupedRow.__displayDate && row[timeDimensionKey]) {\n groupedRow.__displayDate = row[timeDimensionKey]\n }\n\n // Build dimension prefix if dimensions are present\n let dimensionPrefix = ''\n if (hasDimensions) {\n const dimensionValues = dimensionFields.map(field => {\n const value = row[field]\n return getFieldLabel ? getFieldLabel(String(value)) : String(value)\n })\n dimensionPrefix = dimensionValues.join(' / ')\n }\n\n // Add measure values with optional dimension prefix and period suffix\n const shortLabel = generatePeriodShortLabel(periodLabels[periodIndex] || '', periodIndex)\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n const key = dimensionPrefix\n ? `${dimensionPrefix} - ${displayName} (${shortLabel})`\n : `${displayName} (${shortLabel})`\n groupedRow[key] = row[measure]\n }\n }\n\n // Convert to array and sort by day index\n const transformedData = Array.from(groupedByDayIndex.values())\n .sort((a, b) => a.__periodDayIndex - b.__periodDayIndex)\n\n // Generate series keys (using display names to match the data keys)\n const seriesKeys: string[] = []\n\n if (hasDimensions && uniqueDimensionValues) {\n // Generate all combinations of dimension values\n const dimensionCombinations = generateDimensionCombinations(\n dimensionFields,\n uniqueDimensionValues,\n getFieldLabel\n )\n\n // For each dimension combination, create series keys for each measure + period\n for (const dimCombo of dimensionCombinations) {\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n for (let i = 0; i < periodIndices.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i] || '', i)\n seriesKeys.push(`${dimCombo} - ${displayName} (${shortLabel})`)\n }\n }\n }\n } else {\n // No dimensions - generate simple measure + period keys\n for (const measure of measures) {\n const displayName = getFieldLabel ? getFieldLabel(measure) : measure\n for (let i = 0; i < periodIndices.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i] || '', i)\n seriesKeys.push(`${displayName} (${shortLabel})`)\n }\n }\n }\n\n return {\n data: transformedData,\n seriesKeys,\n xAxisKey: '__periodDayIndex'\n }\n}\n\n/**\n * Generate all combinations of dimension values as formatted strings\n */\nfunction generateDimensionCombinations(\n dimensionFields: string[],\n uniqueValues: Map<string, Set<any>>,\n getFieldLabel?: (fieldName: string) => string\n): string[] {\n if (dimensionFields.length === 0) return []\n\n // For single dimension, just return the values\n if (dimensionFields.length === 1) {\n const field = dimensionFields[0]\n const values = Array.from(uniqueValues.get(field) || [])\n return values.map(v => getFieldLabel ? getFieldLabel(String(v)) : String(v))\n }\n\n // For multiple dimensions, generate cartesian product\n const result: string[] = []\n const fieldValues = dimensionFields.map(field =>\n Array.from(uniqueValues.get(field) || [])\n )\n\n function generateCombos(index: number, current: string[]): void {\n if (index === fieldValues.length) {\n const formatted = current.map(v =>\n getFieldLabel ? getFieldLabel(String(v)) : String(v)\n )\n result.push(formatted.join(' / '))\n return\n }\n\n for (const value of fieldValues[index]) {\n generateCombos(index + 1, [...current, value])\n }\n }\n\n generateCombos(0, [])\n return result\n}\n\n/**\n * Format the period day index for display on X-axis\n * Can show as \"Day 1\", \"Day 2\", etc., or as the original date\n */\nexport function formatPeriodDayIndex(\n dayIndex: number,\n displayDate?: string | Date,\n options?: {\n showDayNumber?: boolean\n dateFormat?: 'short' | 'long'\n }\n): string {\n if (options?.showDayNumber) {\n return `Day ${dayIndex + 1}`\n }\n\n if (displayDate) {\n const date = typeof displayDate === 'string' ? new Date(displayDate) : displayDate\n if (!isNaN(date.getTime())) {\n return date.toLocaleDateString('en-US', {\n month: options?.dateFormat === 'long' ? 'long' : 'short',\n day: 'numeric'\n })\n }\n }\n\n return `${dayIndex + 1}`\n}\n\n/**\n * Check if a series key represents a prior period (not the first period)\n * Used for applying different styling to prior period lines\n */\nexport function isPriorPeriodSeries(seriesKey: string, periodLabels: string[]): boolean {\n if (periodLabels.length < 2) return false\n\n // Check if the series key contains any label other than the first period's\n for (let i = 1; i < periodLabels.length; i++) {\n const shortLabel = generatePeriodShortLabel(periodLabels[i], i)\n if (seriesKey.includes(`(${shortLabel})`)) {\n return true\n }\n }\n\n // Also check for \"(Prior\" pattern\n return seriesKey.includes('(Prior')\n}\n\n/**\n * Get the stroke dash array for prior period styling\n */\nexport function getPriorPeriodStrokeDashArray(\n style: 'solid' | 'dashed' | 'dotted' = 'dashed'\n): string | undefined {\n switch (style) {\n case 'solid':\n return undefined\n case 'dashed':\n return '5 5'\n case 'dotted':\n return '2 2'\n default:\n return '5 5'\n }\n}\n","import React, { useState, useMemo } from 'react'\nimport { LineChart as RechartsLineChart, Line, XAxis, YAxis, CartesianGrid, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport AngledXAxisTick from './AngledXAxisTick'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport { transformChartDataWithSeries, formatAxisValue, formatTimeValue, getFieldGranularity } from '../../utils/chartUtils'\nimport { parseTargetValues, spreadTargetValues } from '../../utils/targetUtils'\nimport {\n isComparisonData,\n getPeriodLabels,\n transformForOverlayMode,\n isPriorPeriodSeries,\n getPriorPeriodStrokeDashArray\n} from '../../utils/comparisonUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst LineChart = React.memo(function LineChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\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 // Extract Y-axis fields early for use in useMemo hooks\n // This ensures hooks are always called in the same order\n const yAxisFields = useMemo(() => {\n if (chartConfig?.yAxis) {\n return Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis : [chartConfig.yAxis]\n }\n if (chartConfig?.y) {\n return Array.isArray(chartConfig.y) ? chartConfig.y : [chartConfig.y]\n }\n return []\n }, [chartConfig?.yAxis, chartConfig?.y])\n\n // Dual Y-axis support: extract yAxisAssignment from chartConfig (memoized to prevent object recreation)\n // MUST be called before any early returns to satisfy React hooks rules\n const yAxisAssignment = useMemo(() =>\n chartConfig?.yAxisAssignment || {},\n [chartConfig?.yAxisAssignment]\n )\n\n // Build mapping from series key (label) to original field name (memoized to prevent object recreation)\n // This is needed because seriesKeys use display labels, not field names\n // MUST be called before any early returns to satisfy React hooks rules\n const seriesKeyToField = useMemo(() => {\n const mapping: Record<string, string> = {}\n yAxisFields.forEach((field) => {\n const label = getFieldLabel(field)\n mapping[label] = field\n })\n return mapping\n }, [yAxisFields, getFieldLabel])\n\n try {\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n connectNulls: displayConfig?.connectNulls ?? false\n }\n\n // Extract axis format configs\n const leftYAxisFormat = displayConfig?.leftYAxisFormat\n const rightYAxisFormat = displayConfig?.rightYAxisFormat\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\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data points to display in line chart</div>\n </div>\n </div>\n )\n }\n\n // Validate chartConfig - support both legacy and new formats\n let xAxisField: 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 seriesFields = chartConfig.series || []\n } else if (chartConfig?.x && chartConfig?.y) {\n // Legacy format\n xAxisField = chartConfig.x\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\">Configuration Error</div>\n <div className=\"dc:text-xs\">Invalid or missing chart axis configuration</div>\n </div>\n </div>\n )\n }\n\n if (!xAxisField || 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\">Configuration Error</div>\n <div className=\"dc:text-xs\">Missing required X-axis or Y-axis fields</div>\n </div>\n </div>\n )\n }\n\n // Check if this is comparison data (has __periodIndex metadata)\n const hasComparisonData = isComparisonData(data)\n const priorPeriodStyle = displayConfig?.priorPeriodStyle || 'dashed'\n const priorPeriodOpacity = displayConfig?.priorPeriodOpacity ?? 0.5\n const periodLabels = hasComparisonData ? getPeriodLabels(data) : []\n\n // Transform data based on comparison mode\n let chartData: any[]\n let seriesKeys: string[]\n let effectiveXAxisKey = 'name' // Default X-axis key after transformation\n\n if (hasComparisonData) {\n // For comparison data, always use overlay transformation to align by period day index\n // Both 'separate' and 'overlay' modes use the same data transformation,\n // they differ only in styling (dashed lines, opacity for prior periods in overlay mode)\n const overlayResult = transformForOverlayMode(data, yAxisFields, xAxisField, getFieldLabel)\n chartData = overlayResult.data\n seriesKeys = overlayResult.seriesKeys\n effectiveXAxisKey = '__periodDayIndex'\n } else {\n // Standard mode: use normal transformation\n const standardResult = transformChartDataWithSeries(\n data,\n xAxisField,\n yAxisFields,\n queryObject,\n seriesFields,\n getFieldLabel\n )\n chartData = standardResult.data\n seriesKeys = standardResult.seriesKeys\n }\n\n // Helper to find field from series key, handling comparison suffixes like \"(Current)\" and \"(Prior)\"\n const findFieldFromSeriesKey = (seriesKey: string): string | undefined => {\n // Direct match first\n if (seriesKeyToField[seriesKey]) {\n return seriesKeyToField[seriesKey]\n }\n // For comparison data, strip the period suffix and any dimension prefix\n // Series keys look like: \"Label (Current)\", \"Label (Prior)\", or \"DimValue - Label (Current)\"\n const withoutSuffix = seriesKey.replace(/\\s*\\((Current|Prior)\\)$/, '')\n // Check if it has a dimension prefix (contains \" - \")\n const parts = withoutSuffix.split(' - ')\n const measureLabel = parts[parts.length - 1] // Last part is the measure label\n return seriesKeyToField[measureLabel]\n }\n\n // Determine if we need a right Y-axis\n const hasRightAxis = yAxisFields.some((field) => yAxisAssignment[field] === 'right')\n\n // Get fields for left and right axes for labels\n const leftAxisFields = yAxisFields.filter((f) => (yAxisAssignment[f] || 'left') === 'left')\n const rightAxisFields = yAxisFields.filter((f) => yAxisAssignment[f] === 'right')\n\n // Determine if legend will be shown\n const showLegend = safeDisplayConfig.showLegend\n\n // Use custom chart margins with extra space for Y-axis labels\n const chartMargins = {\n ...CHART_MARGINS,\n left: 40, // Space for left Y-axis label\n right: hasRightAxis ? 40 : 20 // Extra space for right Y-axis label if needed\n }\n\n // Process target values and add to chart data\n const targetValues = parseTargetValues(displayConfig?.target || '')\n const spreadTargets = spreadTargetValues(targetValues, chartData.length)\n\n // Add target data to chart data if targets exist\n let enhancedChartData = chartData\n if (spreadTargets.length > 0) {\n enhancedChartData = chartData.map((dataPoint, index) => ({\n ...dataPoint,\n __target: spreadTargets[index] || null\n }))\n }\n\n // Validate transformed data\n if (!chartData || chartData.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\">No valid data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No valid data points for line chart after transformation</div>\n </div>\n </div>\n )\n }\n\n return (\n <ChartContainer height={height}>\n <RechartsLineChart data={enhancedChartData} margin={chartMargins} accessibilityLayer={false}>\n {safeDisplayConfig.showGrid && (\n <CartesianGrid strokeDasharray=\"3 3\" style={{ pointerEvents: 'none' }} />\n )}\n <XAxis\n dataKey={effectiveXAxisKey}\n type=\"category\"\n tick={<AngledXAxisTick tickFormatter={\n hasComparisonData\n ? (value: string | number, index: number) => {\n // For comparison data, show the date from the current period\n // formatted according to the query's granularity\n const row = chartData[index]\n if (row?.__displayDate) {\n const granularity = getFieldGranularity(queryObject, xAxisField)\n return formatTimeValue(row.__displayDate, granularity)\n }\n return `Period ${Number(value) + 1}`\n }\n : undefined\n } />}\n height={60}\n />\n <YAxis\n yAxisId=\"left\"\n orientation=\"left\"\n tick={{ fontSize: 12 }}\n tickFormatter={leftYAxisFormat ? (value) => formatAxisValue(value, leftYAxisFormat) : undefined}\n label={\n leftAxisFields.length > 0\n ? {\n value: leftYAxisFormat?.label || getFieldLabel(leftAxisFields[0]),\n angle: -90,\n position: 'left',\n style: { textAnchor: 'middle', fontSize: '12px' }\n }\n : undefined\n }\n />\n {hasRightAxis && (\n <YAxis\n yAxisId=\"right\"\n orientation=\"right\"\n tick={{ fontSize: 12 }}\n tickFormatter={rightYAxisFormat ? (value) => formatAxisValue(value, rightYAxisFormat) : undefined}\n label={\n rightAxisFields.length > 0\n ? {\n value: rightYAxisFormat?.label || getFieldLabel(rightAxisFields[0]),\n angle: 90,\n position: 'right',\n style: { textAnchor: 'middle', fontSize: '12px' }\n }\n : undefined\n }\n />\n )}\n {safeDisplayConfig.showTooltip && (\n <ChartTooltip\n formatter={(value: any, name: any) => {\n // Handle null values in tooltip\n if (value === null || value === undefined) {\n return ['No data', name]\n }\n if (name === 'Target') {\n // Use left Y-axis format for target values\n return [formatAxisValue(value, leftYAxisFormat), 'Target Value']\n }\n\n // Determine which axis format to use based on series name\n const originalField = findFieldFromSeriesKey(name)\n const axisId = originalField && yAxisAssignment[originalField] === 'right' ? 'right' : 'left'\n const formatConfig = axisId === 'right' ? rightYAxisFormat : leftYAxisFormat\n // Series name is already formatted (e.g., \"Total Lines of Code (Current)\")\n return [formatAxisValue(value, formatConfig), name]\n }}\n labelFormatter={\n hasComparisonData\n ? (label: any, payload: any) => {\n // For comparison data, show the date from the current period\n // formatted according to the query's granularity\n if (payload && payload.length > 0) {\n const row = payload[0]?.payload\n if (row?.__displayDate) {\n const granularity = getFieldGranularity(queryObject, xAxisField)\n return formatTimeValue(row.__displayDate, granularity)\n }\n }\n return `Period ${Number(label) + 1}`\n }\n : undefined\n }\n />\n )}\n {showLegend && (\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '25px' }}\n iconType=\"line\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n {seriesKeys.map((seriesKey, index) => {\n // Look up the original field name to get its axis assignment\n const originalField = findFieldFromSeriesKey(seriesKey)\n const axisId = originalField && yAxisAssignment[originalField] === 'right' ? 'right' : 'left'\n\n // Determine if this is a prior period series (for styling)\n const isPriorPeriod = hasComparisonData && isPriorPeriodSeries(seriesKey, periodLabels)\n const strokeDashArray = isPriorPeriod ? getPriorPeriodStrokeDashArray(priorPeriodStyle) : undefined\n const opacity = isPriorPeriod ? priorPeriodOpacity : 1\n\n // When drill is enabled, show persistent dots for better click targets\n const lineColor = (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n\n return (\n <Line\n key={seriesKey}\n type=\"monotone\"\n dataKey={seriesKey}\n yAxisId={axisId}\n stroke={lineColor}\n strokeWidth={isPriorPeriod ? 1.5 : 2}\n strokeDasharray={strokeDashArray}\n dot={isPriorPeriod ? false : (props: any) => {\n const { cx, cy, payload, key } = props\n if (cx === undefined || cy === undefined) return null\n\n const handleClick = (event: React.MouseEvent) => {\n event.stopPropagation()\n event.preventDefault()\n if (onDataPointClick) {\n onDataPointClick({\n dataPoint: payload,\n clickedField: originalField || seriesKey,\n xValue: payload.name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }\n\n // When drill is enabled, render clickable dots with background to mask grid\n if (drillEnabled && onDataPointClick) {\n return (\n <g key={key}>\n {/* Background to mask grid lines - uses theme surface color */}\n <circle\n cx={cx}\n cy={cy}\n r={6}\n fill=\"var(--dc-surface)\"\n style={{ pointerEvents: 'none' }}\n />\n {/* Visible dot with click handler */}\n <circle\n cx={cx}\n cy={cy}\n r={4}\n fill=\"var(--dc-surface)\"\n stroke={lineColor}\n strokeWidth={2}\n cursor=\"pointer\"\n onClick={(e: React.MouseEvent<SVGCircleElement>) => {\n handleClick(e as unknown as React.MouseEvent)\n }}\n />\n </g>\n )\n }\n\n // Non-drill mode: simple small dot\n return (\n <circle\n key={key}\n cx={cx}\n cy={cy}\n r={3}\n fill={lineColor}\n />\n )\n }}\n activeDot={false}\n strokeOpacity={\n hoveredLegend\n ? (hoveredLegend === seriesKey ? 1 : 0.3)\n : opacity\n }\n connectNulls={safeDisplayConfig.connectNulls}\n />\n )\n })}\n {spreadTargets.length > 0 && (\n <>\n {/* White background line */}\n <Line\n type=\"monotone\"\n dataKey=\"__target\"\n yAxisId=\"left\"\n stroke=\"#ffffff\"\n strokeWidth={2}\n dot={false}\n activeDot={false}\n connectNulls={false}\n />\n {/* Grey dashed line on top */}\n <Line\n type=\"monotone\"\n dataKey=\"__target\"\n yAxisId=\"left\"\n name=\"Target\"\n stroke=\"#8B5CF6\"\n strokeWidth={2}\n strokeDasharray=\"2 3\"\n dot={false}\n activeDot={false}\n connectNulls={false}\n />\n </>\n )}\n </RechartsLineChart>\n </ChartContainer>\n )\n } catch (error) {\n // 'LineChart 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\">Line Chart Error</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : 'Unknown rendering error'}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">Check the data and configuration</div>\n </div>\n </div>\n )\n }\n})\n\nexport default LineChart\n"],"names":["isComparisonData","data","getPeriodLabels","labels","row","getPeriodIndices","indices","a","b","generatePeriodShortLabel","_periodLabel","index","transformForSeparateMode","measures","_timeDimensionKey","periodLabels","seriesKeys","measure","shortLabel","key","detectDimensionFields","timeDimensionKey","metadataFields","firstRow","dimensions","getUniqueDimensionValues","dimensionFields","values","field","transformForOverlayMode","getFieldLabel","periodIndices","hasDimensions","uniqueDimensionValues","groupedByDayIndex","dayIndex","periodIndex","groupedRow","dimensionPrefix","value","displayName","transformedData","dimensionCombinations","generateDimensionCombinations","dimCombo","i","uniqueValues","v","result","fieldValues","generateCombos","current","formatted","formatPeriodDayIndex","displayDate","options","date","isPriorPeriodSeries","seriesKey","getPriorPeriodStrokeDashArray","style","LineChart","React","chartConfig","displayConfig","queryObject","height","colorPalette","onDataPointClick","drillEnabled","hoveredLegend","setHoveredLegend","useState","useCubeFieldLabel","yAxisFields","useMemo","yAxisAssignment","seriesKeyToField","mapping","label","safeDisplayConfig","leftYAxisFormat","rightYAxisFormat","jsx","jsxs","xAxisField","seriesFields","hasComparisonData","priorPeriodStyle","priorPeriodOpacity","chartData","effectiveXAxisKey","overlayResult","standardResult","transformChartDataWithSeries","findFieldFromSeriesKey","parts","measureLabel","hasRightAxis","leftAxisFields","f","rightAxisFields","showLegend","chartMargins","CHART_MARGINS","targetValues","parseTargetValues","spreadTargets","spreadTargetValues","enhancedChartData","dataPoint","ChartContainer","RechartsLineChart","CartesianGrid","XAxis","AngledXAxisTick","granularity","getFieldGranularity","formatTimeValue","YAxis","formatAxisValue","ChartTooltip","name","originalField","formatConfig","payload","Legend","o","axisId","isPriorPeriod","strokeDashArray","opacity","lineColor","CHART_COLORS","Line","props","cx","cy","handleClick","event","e","Fragment","error"],"mappings":"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"}
|