mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-13 13:48:59 +02:00
feat: create flags created vs archived chart
This commit is contained in:
parent
df01f53aed
commit
ffffe02792
@ -0,0 +1,87 @@
|
||||
import type { FC } from 'react';
|
||||
import { Box, Paper, Typography, styled } from '@mui/material';
|
||||
import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
|
||||
import { ChartTooltipContainer } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
|
||||
|
||||
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
width: 200,
|
||||
}));
|
||||
|
||||
const StyledFlagItem = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: theme.spacing(0.5),
|
||||
}));
|
||||
|
||||
interface CreationArchiveRatioTooltipProps {
|
||||
tooltip: TooltipState | null;
|
||||
}
|
||||
|
||||
export const CreationArchiveRatioTooltip: FC<
|
||||
CreationArchiveRatioTooltipProps
|
||||
> = ({ tooltip }) => {
|
||||
if (!tooltip?.dataPoints) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter for the percentage line dataset
|
||||
const ratioDataPoint = tooltip.dataPoints.find(
|
||||
(point) => point.dataset.label === 'Flags archived / Flags created',
|
||||
);
|
||||
|
||||
if (!ratioDataPoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the raw data to extract counts
|
||||
const rawData = ratioDataPoint.raw as any;
|
||||
|
||||
if (!rawData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const archivedCount = rawData.archivedFlags || 0;
|
||||
const createdCount = rawData.totalCreatedFlags || 0;
|
||||
const ratio = Math.round(ratioDataPoint.parsed.y as number);
|
||||
|
||||
return (
|
||||
<ChartTooltipContainer tooltip={tooltip}>
|
||||
<StyledTooltipItemContainer elevation={3}>
|
||||
<Typography
|
||||
variant='body2'
|
||||
component='div'
|
||||
fontWeight='bold'
|
||||
sx={{ marginBottom: 1 }}
|
||||
>
|
||||
Ratio {ratio}%
|
||||
</Typography>
|
||||
|
||||
<StyledFlagItem>
|
||||
<Typography variant='body2' component='span'>
|
||||
<Typography sx={{ color: '#4caf50' }} component='span'>
|
||||
{'● '}
|
||||
</Typography>
|
||||
Flags created
|
||||
</Typography>
|
||||
<Typography variant='body2' component='span'>
|
||||
{createdCount}
|
||||
</Typography>
|
||||
</StyledFlagItem>
|
||||
|
||||
<StyledFlagItem>
|
||||
<Typography variant='body2' component='span'>
|
||||
<Typography sx={{ color: '#9e9e9e' }} component='span'>
|
||||
{'● '}
|
||||
</Typography>
|
||||
Flags archived
|
||||
</Typography>
|
||||
<Typography variant='body2' component='span'>
|
||||
{archivedCount}
|
||||
</Typography>
|
||||
</StyledFlagItem>
|
||||
</StyledTooltipItemContainer>
|
||||
</ChartTooltipContainer>
|
||||
);
|
||||
};
|
@ -0,0 +1,101 @@
|
||||
import type { FC } from 'react';
|
||||
import { Box, Paper, Typography, styled } from '@mui/material';
|
||||
import type { TooltipState } from '../../components/LineChart/ChartTooltip/ChartTooltip.tsx';
|
||||
import { ChartTooltipContainer } from '../../components/LineChart/ChartTooltip/ChartTooltip.tsx';
|
||||
|
||||
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,
|
||||
}) => {
|
||||
if (!tooltip?.dataPoints) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter for created flag type datasets only
|
||||
const createdFlagDataPoints = tooltip.dataPoints.filter((point) =>
|
||||
point.dataset.label?.startsWith('Created:'),
|
||||
);
|
||||
|
||||
if (createdFlagDataPoints.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the data from the first point (they all have the same raw data)
|
||||
const rawData = createdFlagDataPoints[0]?.raw as any;
|
||||
|
||||
if (!rawData?.createdFlagsByType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Flag type colors matching the chart
|
||||
const flagTypeColors = [
|
||||
'#66bb6a', // theme.palette.success.border
|
||||
'#4caf50', // theme.palette.success.main
|
||||
'#388e3c', // theme.palette.success.dark
|
||||
'#4D8007',
|
||||
'#7D935E',
|
||||
];
|
||||
|
||||
// Get flag type names from the chart datasets
|
||||
const flagTypeNames = createdFlagDataPoints.map(
|
||||
(point) => point.dataset.label?.replace('Created: ', '') || '',
|
||||
);
|
||||
|
||||
// Create entries for each flag type with count > 0
|
||||
const flagTypeEntries = Object.entries(rawData.createdFlagsByType)
|
||||
.filter(([, count]) => (count as number) > 0)
|
||||
.map(([flagType, count], index) => ({
|
||||
type: flagType,
|
||||
count: count as number,
|
||||
color:
|
||||
flagTypeColors[flagTypeNames.indexOf(flagType)] ||
|
||||
flagTypeColors[index % flagTypeColors.length],
|
||||
}));
|
||||
|
||||
if (flagTypeEntries.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ChartTooltipContainer tooltip={tooltip}>
|
||||
<StyledTooltipItemContainer elevation={3}>
|
||||
<Typography
|
||||
variant='body2'
|
||||
component='div'
|
||||
fontWeight='bold'
|
||||
sx={{ marginBottom: 1 }}
|
||||
>
|
||||
Flag type
|
||||
</Typography>
|
||||
|
||||
{flagTypeEntries.map(({ type, count, color }) => (
|
||||
<StyledFlagTypeItem key={type}>
|
||||
<Typography variant='body2' component='span'>
|
||||
<Typography sx={{ color }} component='span'>
|
||||
{'● '}
|
||||
</Typography>
|
||||
{type.charAt(0).toUpperCase() + type.slice(1)}
|
||||
</Typography>
|
||||
<Typography variant='body2' component='span'>
|
||||
{count}
|
||||
</Typography>
|
||||
</StyledFlagTypeItem>
|
||||
))}
|
||||
</StyledTooltipItemContainer>
|
||||
</ChartTooltipContainer>
|
||||
);
|
||||
};
|
@ -0,0 +1,76 @@
|
||||
import type { FC } from 'react';
|
||||
import { Box, Typography, Link, styled } from '@mui/material';
|
||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||
import InfoOutlined from '@mui/icons-material/InfoOutlined';
|
||||
import Lightbulb from '@mui/icons-material/LightbulbOutlined';
|
||||
import { StatsExplanation } from 'component/insights/InsightsCharts.styles';
|
||||
|
||||
const StyledRatioContainer = styled(Box)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.elevation1,
|
||||
borderRadius: theme.spacing(2),
|
||||
padding: theme.spacing(2),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(0.5),
|
||||
}));
|
||||
|
||||
const StyledPercentageRow = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
const StyledRatioTypography = styled(Typography)(({ theme }) => ({
|
||||
color: theme.palette.primary.main,
|
||||
fontFamily: 'inherit',
|
||||
fontSize: '20px',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: 700,
|
||||
lineHeight: '28px',
|
||||
}));
|
||||
|
||||
const StyledInfoIcon = styled(InfoOutlined)(({ theme }) => ({
|
||||
color: theme.palette.text.secondary,
|
||||
}));
|
||||
|
||||
const StyledLink = styled(Link)(({ theme }) => ({
|
||||
color: theme.palette.primary.main,
|
||||
textDecoration: 'none',
|
||||
'&:hover': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
}));
|
||||
|
||||
interface CreationArchiveStatsProps {
|
||||
currentRatio: number;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export const CreationArchiveStats: FC<CreationArchiveStatsProps> = ({
|
||||
currentRatio,
|
||||
isLoading,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<StyledRatioContainer>
|
||||
<StyledPercentageRow>
|
||||
<StyledRatioTypography>
|
||||
{isLoading ? '...' : `${currentRatio}%`}
|
||||
</StyledRatioTypography>
|
||||
<HelpIcon tooltip='Ratio of archived flags to created flags'>
|
||||
<StyledInfoIcon />
|
||||
</HelpIcon>
|
||||
</StyledPercentageRow>
|
||||
<Typography variant='body2'>Current ratio</Typography>
|
||||
</StyledRatioContainer>
|
||||
<StatsExplanation>
|
||||
<Lightbulb color='primary' />
|
||||
Do you create more flags than you archive? Or do you have good
|
||||
process for cleaning up?
|
||||
</StatsExplanation>
|
||||
<StyledLink href='/search?lifecycle=IS:completed' variant='body2'>
|
||||
View flags in cleanup stage
|
||||
</StyledLink>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user