diff --git a/frontend/src/component/impact-metrics/ImpactMetricsChart.tsx b/frontend/src/component/impact-metrics/ImpactMetricsChart.tsx index fc9b7f871a..2577bacb60 100644 --- a/frontend/src/component/impact-metrics/ImpactMetricsChart.tsx +++ b/frontend/src/component/impact-metrics/ImpactMetricsChart.tsx @@ -1,6 +1,17 @@ import type { FC, ReactNode } from 'react'; import { useMemo } from 'react'; -import { Alert } from '@mui/material'; +import { Alert, Box, styled, useTheme } from '@mui/material'; +import { + BarElement, + CategoryScale, + Chart as ChartJS, + LinearScale, + TimeScale, + Tooltip, + Legend, +} from 'chart.js'; +import { Bar } from 'react-chartjs-2'; +import 'chartjs-adapter-date-fns'; import { LineChart, NotEnoughData, @@ -11,11 +22,27 @@ import { getDisplayFormat, getTimeUnit, formatLargeNumbers } from './utils.ts'; import { fromUnixTime } from 'date-fns'; import { useChartData } from './hooks/useChartData.ts'; +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + TimeScale, + Tooltip, + Legend, +); + +const StyledBarChartContainer = styled(Box)({ + position: 'relative', + width: '100%', + height: '100%', +}); + type ImpactMetricsChartProps = { selectedSeries: string; selectedRange: 'hour' | 'day' | 'week' | 'month'; selectedLabels: Record; beginAtZero: boolean; + chartType?: 'line' | 'bar'; aspectRatio?: number; overrideOptions?: Record; errorTitle?: string; @@ -28,12 +55,14 @@ export const ImpactMetricsChart: FC = ({ selectedRange, selectedLabels, beginAtZero, + chartType = 'bar', aspectRatio, overrideOptions = {}, errorTitle = 'Failed to load impact metrics. Please check if Prometheus is configured and the feature flag is enabled.', emptyDataDescription = 'Send impact metrics using Unleash SDK and select data series to view the chart.', noSeriesPlaceholder, }) => { + const theme = useTheme(); const { data: { start, end, series: timeSeriesData }, loading: dataLoading, @@ -56,8 +85,55 @@ export const ImpactMetricsChart: FC = ({ type: 'constant', }); + const barPlaceholderData = useMemo( + () => ({ + labels: placeholderData.labels, + datasets: placeholderData.datasets.map((dataset) => ({ + label: dataset.label, + data: dataset.data, + backgroundColor: theme.palette.divider, + borderColor: theme.palette.divider, + borderWidth: 1, + })), + }), + [placeholderData, theme], + ); + const data = useChartData(timeSeriesData); + const barChartData = useMemo(() => { + if (!timeSeriesData || timeSeriesData.length === 0) { + return { + labels: [], + datasets: [ + { + data: [], + backgroundColor: theme.palette.primary.main, + borderColor: theme.palette.primary.main, + borderWidth: 1, + }, + ], + }; + } + + return { + labels: data.labels, + datasets: data.datasets.map((dataset) => ({ + label: dataset.label, + data: dataset.data, + backgroundColor: + typeof dataset.backgroundColor === 'string' + ? dataset.backgroundColor + : theme.palette.primary.main, + borderColor: + typeof dataset.borderColor === 'string' + ? dataset.borderColor + : theme.palette.primary.main, + borderWidth: 1, + })), + }; + }, [data, timeSeriesData, theme]); + const hasError = !!dataError; const isLoading = dataLoading; const shouldShowPlaceholder = !selectedSeries || isLoading || hasError; @@ -144,12 +220,42 @@ export const ImpactMetricsChart: FC = ({ return ( <> {hasError ? {errorTitle} : null} - + {chartType === 'bar' ? ( + + + {cover && ( + + {cover} + + )} + + ) : ( + + )} ); };