mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
experiment: bar chart
This commit is contained in:
parent
3b6613360c
commit
8716d5af47
@ -1,6 +1,17 @@
|
|||||||
import type { FC, ReactNode } from 'react';
|
import type { FC, ReactNode } from 'react';
|
||||||
import { useMemo } 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 {
|
import {
|
||||||
LineChart,
|
LineChart,
|
||||||
NotEnoughData,
|
NotEnoughData,
|
||||||
@ -11,11 +22,27 @@ import { getDisplayFormat, getTimeUnit, formatLargeNumbers } from './utils.ts';
|
|||||||
import { fromUnixTime } from 'date-fns';
|
import { fromUnixTime } from 'date-fns';
|
||||||
import { useChartData } from './hooks/useChartData.ts';
|
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 = {
|
type ImpactMetricsChartProps = {
|
||||||
selectedSeries: string;
|
selectedSeries: string;
|
||||||
selectedRange: 'hour' | 'day' | 'week' | 'month';
|
selectedRange: 'hour' | 'day' | 'week' | 'month';
|
||||||
selectedLabels: Record<string, string[]>;
|
selectedLabels: Record<string, string[]>;
|
||||||
beginAtZero: boolean;
|
beginAtZero: boolean;
|
||||||
|
chartType?: 'line' | 'bar';
|
||||||
aspectRatio?: number;
|
aspectRatio?: number;
|
||||||
overrideOptions?: Record<string, unknown>;
|
overrideOptions?: Record<string, unknown>;
|
||||||
errorTitle?: string;
|
errorTitle?: string;
|
||||||
@ -28,12 +55,14 @@ export const ImpactMetricsChart: FC<ImpactMetricsChartProps> = ({
|
|||||||
selectedRange,
|
selectedRange,
|
||||||
selectedLabels,
|
selectedLabels,
|
||||||
beginAtZero,
|
beginAtZero,
|
||||||
|
chartType = 'bar',
|
||||||
aspectRatio,
|
aspectRatio,
|
||||||
overrideOptions = {},
|
overrideOptions = {},
|
||||||
errorTitle = 'Failed to load impact metrics. Please check if Prometheus is configured and the feature flag is enabled.',
|
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.',
|
emptyDataDescription = 'Send impact metrics using Unleash SDK and select data series to view the chart.',
|
||||||
noSeriesPlaceholder,
|
noSeriesPlaceholder,
|
||||||
}) => {
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
const {
|
const {
|
||||||
data: { start, end, series: timeSeriesData },
|
data: { start, end, series: timeSeriesData },
|
||||||
loading: dataLoading,
|
loading: dataLoading,
|
||||||
@ -56,8 +85,55 @@ export const ImpactMetricsChart: FC<ImpactMetricsChartProps> = ({
|
|||||||
type: 'constant',
|
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 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 hasError = !!dataError;
|
||||||
const isLoading = dataLoading;
|
const isLoading = dataLoading;
|
||||||
const shouldShowPlaceholder = !selectedSeries || isLoading || hasError;
|
const shouldShowPlaceholder = !selectedSeries || isLoading || hasError;
|
||||||
@ -144,12 +220,42 @@ export const ImpactMetricsChart: FC<ImpactMetricsChartProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hasError ? <Alert severity='error'>{errorTitle}</Alert> : null}
|
{hasError ? <Alert severity='error'>{errorTitle}</Alert> : null}
|
||||||
<LineChart
|
{chartType === 'bar' ? (
|
||||||
data={notEnoughData || isLoading ? placeholderData : data}
|
<StyledBarChartContainer>
|
||||||
aspectRatio={aspectRatio}
|
<Bar
|
||||||
overrideOptions={chartOptions}
|
data={
|
||||||
cover={cover}
|
(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}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user