1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

experiment: bar chart

This commit is contained in:
Tymoteusz Czech 2025-07-08 19:55:07 +02:00
parent 3b6613360c
commit 8716d5af47
No known key found for this signature in database
GPG Key ID: 133555230D88D75F

View File

@ -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<string, string[]>;
beginAtZero: boolean;
chartType?: 'line' | 'bar';
aspectRatio?: number;
overrideOptions?: Record<string, unknown>;
errorTitle?: string;
@ -28,12 +55,14 @@ export const ImpactMetricsChart: FC<ImpactMetricsChartProps> = ({
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<ImpactMetricsChartProps> = ({
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<ImpactMetricsChartProps> = ({
return (
<>
{hasError ? <Alert severity='error'>{errorTitle}</Alert> : null}
<LineChart
data={notEnoughData || isLoading ? placeholderData : data}
aspectRatio={aspectRatio}
overrideOptions={chartOptions}
cover={cover}
/>
{chartType === 'bar' ? (
<StyledBarChartContainer>
<Bar
data={
(notEnoughData || isLoading
? barPlaceholderData
: barChartData) as any
}
options={chartOptions as any}
height={aspectRatio ? 100 : undefined}
width={aspectRatio ? 100 * aspectRatio : undefined}
/>
{cover && (
<Box
sx={{
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(255, 255, 255, 0.8)',
zIndex: 1,
}}
>
{cover}
</Box>
)}
</StyledBarChartContainer>
) : (
<LineChart
data={notEnoughData || isLoading ? placeholderData : data}
aspectRatio={aspectRatio}
overrideOptions={chartOptions}
cover={cover}
/>
)}
</>
);
};