1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-19 17:52:45 +02:00

Show tooltip on group instead of single graph bar (#10546)

The tooltip should show you the ratio of the group and the numbers for
both archived and created.

The tooltip's position is averaged between all the bars in the group.

<img width="335" height="262" alt="image"
src="https://github.com/user-attachments/assets/d62a4bdc-ba07-4eea-8cbf-6e42793804b2"
/>


This still throws the same errors as before. Not sure exactly what's
going on with the custom tooltip, but I'll investigate it in a
follow-up.

Closes 1-4017.
This commit is contained in:
Thomas Heartman 2025-08-28 10:26:46 +02:00 committed by GitHub
parent 8ba36ee9a2
commit 9eb872de82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 157 deletions

View File

@ -5,7 +5,6 @@ import { useProjectChartData } from 'component/insights/hooks/useProjectChartDat
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData'; import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import { Chart } from 'react-chartjs-2';
import { import {
CategoryScale, CategoryScale,
LinearScale, LinearScale,
@ -19,13 +18,11 @@ import {
Filler, Filler,
} from 'chart.js'; } from 'chart.js';
import { useLocationSettings } from 'hooks/useLocationSettings'; import { useLocationSettings } from 'hooks/useLocationSettings';
import { import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
ChartTooltip,
type TooltipState,
} from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { createTooltip } from 'component/insights/components/LineChart/createTooltip';
import { CreationArchiveTooltip } from './CreationArchiveTooltip.tsx';
import type { WeekData, RawWeekData } from './types.ts'; import type { WeekData, RawWeekData } from './types.ts';
import { createTooltip } from 'component/insights/components/LineChart/createTooltip.ts';
import { CreationArchiveRatioTooltip } from './CreationArchiveRatioTooltip.tsx';
import { Chart } from 'react-chartjs-2';
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
@ -144,6 +141,10 @@ export const CreationArchiveChart: FC<ICreationArchiveChartProps> = ({
data={data} data={data}
options={{ options={{
responsive: true, responsive: true,
interaction: {
mode: 'index',
intersect: false,
},
plugins: { plugins: {
legend: { legend: {
position: 'bottom' as const, position: 'bottom' as const,
@ -156,7 +157,7 @@ export const CreationArchiveChart: FC<ICreationArchiveChartProps> = ({
}, },
tooltip: { tooltip: {
enabled: false, enabled: false,
position: 'nearest', position: 'average',
external: createTooltip(setTooltip), external: createTooltip(setTooltip),
}, },
}, },
@ -187,13 +188,7 @@ export const CreationArchiveChart: FC<ICreationArchiveChartProps> = ({
height={100} height={100}
width={250} width={250}
/> />
{tooltip?.dataPoints?.some( <CreationArchiveRatioTooltip tooltip={tooltip} />
(point) => point.dataset.label !== 'Flags archived',
) ? (
<CreationArchiveTooltip tooltip={tooltip} />
) : (
<ChartTooltip tooltip={tooltip} />
)}
</> </>
); );
}; };

View File

@ -1,24 +1,38 @@
import type { FC } from 'react'; import type { FC } from 'react';
import { Box, Paper, Typography, styled, useTheme } from '@mui/material'; import { Paper, Typography, styled } from '@mui/material';
import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip'; import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { ChartTooltipContainer } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip'; import { ChartTooltipContainer } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import type { Theme } from '@mui/material/styles/createTheme';
import type { WeekData } from './types.ts'; import type { WeekData } from './types.ts';
const getRatioTooltipColors = (theme: Theme) => ({
CREATED: theme.palette.success.main,
ARCHIVED: theme.palette.background.application,
});
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({ const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2), padding: theme.spacing(2),
width: 200, width: 200,
})); }));
const StyledFlagItem = styled(Box)(({ theme }) => ({ const DataList = styled('dl')(({ theme }) => ({
margin: 0,
}));
const DataRow = styled('div', {
shouldForwardProp: (prop) => prop !== 'dataType',
})<{ dataType: 'archived' | 'created' }>(({ theme, dataType }) => ({
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',
marginBottom: theme.spacing(0.5), whiteSpace: 'nowrap',
fontSize: theme.typography.body2.fontSize,
'::before': {
content: '" "',
display: 'inline-block',
height: '.65rem',
aspectRatio: '1/1',
borderRadius: '50%',
backgroundColor:
dataType === 'archived'
? theme.palette.charts.A2
: theme.palette.charts.A1,
},
})); }));
interface CreationArchiveRatioTooltipProps { interface CreationArchiveRatioTooltipProps {
@ -28,30 +42,14 @@ interface CreationArchiveRatioTooltipProps {
export const CreationArchiveRatioTooltip: FC< export const CreationArchiveRatioTooltip: FC<
CreationArchiveRatioTooltipProps CreationArchiveRatioTooltipProps
> = ({ tooltip }) => { > = ({ tooltip }) => {
const theme = useTheme();
const colors = getRatioTooltipColors(theme);
if (!tooltip?.dataPoints) { if (!tooltip?.dataPoints) {
return null; return null;
} }
const ratioDataPoint = tooltip.dataPoints.find( const rawData = tooltip.dataPoints[0].raw as WeekData;
(point) => point.dataset.label === 'Flags archived / Flags created',
);
if (!ratioDataPoint) {
return null;
}
const rawData = ratioDataPoint.raw as WeekData;
if (!rawData) {
return null;
}
const archivedCount = rawData.archivedFlags || 0; const archivedCount = rawData.archivedFlags || 0;
const createdCount = rawData.totalCreatedFlags || 0; const createdCount = rawData.totalCreatedFlags || 0;
const ratio = Math.round(ratioDataPoint.parsed.y as number); const ratio = Math.round((archivedCount / createdCount) * 100);
return ( return (
<ChartTooltipContainer tooltip={tooltip}> <ChartTooltipContainer tooltip={tooltip}>
@ -65,35 +63,16 @@ export const CreationArchiveRatioTooltip: FC<
Ratio {ratio}% Ratio {ratio}%
</Typography> </Typography>
<StyledFlagItem> <DataList>
<Typography variant='body2' component='span'> <DataRow dataType='archived'>
<Typography <dt>Flags archived</dt>
sx={{ color: colors.CREATED }} <dd>{archivedCount}</dd>
component='span' </DataRow>
> <DataRow dataType='created'>
{'● '} <dt>Flags created</dt>
</Typography> <dd>{createdCount}</dd>
Flags created </DataRow>
</Typography> </DataList>
<Typography variant='body2' component='span'>
{createdCount}
</Typography>
</StyledFlagItem>
<StyledFlagItem>
<Typography variant='body2' component='span'>
<Typography
sx={{ color: colors.ARCHIVED }}
component='span'
>
{'● '}
</Typography>
Flags archived
</Typography>
<Typography variant='body2' component='span'>
{archivedCount}
</Typography>
</StyledFlagItem>
</StyledTooltipItemContainer> </StyledTooltipItemContainer>
</ChartTooltipContainer> </ChartTooltipContainer>
); );

View File

@ -1,77 +0,0 @@
import type { FC } from 'react';
import { Box, Paper, Typography, styled, useTheme } from '@mui/material';
import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { ChartTooltipContainer } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { getFlagTypeColors } from './flagTypeColors.ts';
import type { WeekData } from './types.ts';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2),
width: 240,
}));
const StyledFlagTypeItem = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}));
interface CreationArchiveTooltipProps {
tooltip: TooltipState | null;
}
export const CreationArchiveTooltip: FC<CreationArchiveTooltipProps> = ({
tooltip,
}) => {
const theme = useTheme();
if (!tooltip?.dataPoints) {
return null;
}
const createdFlagDataPoints = tooltip.dataPoints.filter(
(point) =>
point.dataset.label !== 'Archived flags' &&
point.dataset.label !== 'Flags archived / Flags created',
);
if (createdFlagDataPoints.length === 0) {
return null;
}
const rawData = createdFlagDataPoints[0]?.raw as WeekData;
const flagTypeNames = createdFlagDataPoints.map(
(point) => point.dataset.label || '',
);
const flagTypeColors = getFlagTypeColors(theme);
return (
<ChartTooltipContainer tooltip={tooltip}>
<StyledTooltipItemContainer elevation={3}>
<Typography
variant='body2'
component='div'
fontWeight='bold'
sx={{ marginBottom: 1 }}
>
Flag type
</Typography>
<Typography variant='body2' component='span'>
<Typography
sx={{ color: flagTypeColors[0] }}
component='span'
>
{'● '}
</Typography>
Total created:
</Typography>
<Typography variant='body2' component='span'>
{rawData.totalCreatedFlags}
</Typography>
</StyledTooltipItemContainer>
</ChartTooltipContainer>
);
};

View File

@ -1,10 +0,0 @@
// todo (lifecycleGraphs): delete this file
import type { Theme } from '@mui/material';
export const getFlagTypeColors = (theme: Theme) => [
theme.palette.success.border,
theme.palette.success.main,
theme.palette.success.dark,
'#4D8007',
'#7D935E',
];