1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-17 13:46:47 +02:00
unleash.unleash/frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx
Thomas Heartman 18591dd017
fix: use the correct design token color for the health chart background (#8783)
This change swaps out the color of the health chart "unfilled" section
for `theme.palette.background.application`. This is the same color
that's used in the sketches, so it should apply better for dark mode.

Why? I noticed that the graph looks choppy in dark mode, so figured
I'd go and investigate. This update makes it look a lot smoother.

Light mode looks the same as before.

Before (notice the leaking light grey):

![image](https://github.com/user-attachments/assets/535ca24b-756b-460c-a7ab-78daf28d68ba)


After:

![image](https://github.com/user-attachments/assets/98d4c0de-bde3-4d10-9210-fdd0bf5dc572)
2024-11-18 14:07:40 +02:00

176 lines
6.1 KiB
TypeScript

import { styled, useTheme, Typography } from '@mui/material';
import { Link } from 'react-router-dom';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { HealthGridTile } from './ProjectHealthGrid.styles';
import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber';
const ChartRadius = 40;
const ChartStrokeWidth = 13;
const ChartTotalWidth = ChartRadius * 2 + ChartStrokeWidth;
const ChartContainerWidth = 100;
const TextContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}));
const ChartRow = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'flex-start',
gap: theme.spacing(2),
}));
const SVGWrapper = styled('div')(({ theme }) => ({
flex: 'none',
height: 85,
width: ChartContainerWidth,
position: 'relative',
}));
const StyledSVG = styled('svg')({
position: 'absolute',
});
const BigText = styled('span')(({ theme }) => ({
fontSize: theme.typography.h1.fontSize,
}));
const UnhealthyStatContainer = styled('div')(({ theme }) => ({
flex: 'none',
display: 'grid',
placeItems: 'center',
width: ChartContainerWidth,
}));
const UnhealthyStatText = styled('p')(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '50%',
backgroundColor:
theme.mode === 'light'
? theme.palette.background.elevation2
: '#302E42', // in dark mode, elevation2 and elevation1 are the same color. This is an alternative
width: ChartTotalWidth,
height: ChartTotalWidth,
overflow: 'hidden',
}));
const UnhealthyFlagBox = ({ flagCount }: { flagCount: number }) => {
const flagWord = flagCount === 1 ? 'flag' : 'flags';
return (
<UnhealthyStatContainer>
<UnhealthyStatText>
<BigText>
<PrettifyLargeNumber
value={flagCount}
threshold={1000}
precision={1}
/>
</BigText>
<span>unhealthy</span>
<span>{flagWord}</span>
</UnhealthyStatText>
</UnhealthyStatContainer>
);
};
const Wrapper = styled(HealthGridTile)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around',
gap: theme.spacing(2),
}));
export const ProjectHealth = () => {
const projectId = useRequiredPathParam('projectId');
const {
data: { averageHealth, staleFlags },
} = useProjectStatus(projectId);
const { isOss } = useUiConfig();
const theme = useTheme();
const circumference = 2 * Math.PI * ChartRadius; //
const gapLength = 0.3;
const filledLength = 1 - gapLength;
const offset = 0.75 - gapLength / 2;
const healthLength = (averageHealth / 100) * circumference * 0.7;
const healthColor =
averageHealth >= 0 && averageHealth <= 24
? theme.palette.error.main
: averageHealth >= 25 && averageHealth <= 74
? theme.palette.warning.border
: theme.palette.success.border;
return (
<Wrapper>
<ChartRow>
<SVGWrapper>
<StyledSVG viewBox='0 0 100 100'>
<circle
cx='50'
cy='50'
r={ChartRadius}
fill='none'
stroke={theme.palette.background.application}
strokeWidth={ChartStrokeWidth}
strokeDasharray={`${filledLength * circumference} ${gapLength * circumference}`}
strokeDashoffset={offset * circumference}
/>
<circle
cx='50'
cy='50'
r={ChartRadius}
fill='none'
stroke={healthColor}
strokeWidth={ChartStrokeWidth}
strokeDasharray={`${healthLength} ${circumference - healthLength}`}
strokeDashoffset={offset * circumference}
/>
<text
x='50'
y='50'
textAnchor='middle'
dominantBaseline='middle'
fill={theme.palette.text.primary}
fontSize={theme.typography.h1.fontSize}
>
{averageHealth}%
</text>
</StyledSVG>
</SVGWrapper>
<TextContainer>
<Typography>
On average, your project health has remained at{' '}
{averageHealth}% the last 4 weeks
</Typography>
{!isOss() && (
<Link to={`/insights?project=IS%3A${projectId}`}>
View health over time
</Link>
)}
</TextContainer>
</ChartRow>
<ChartRow>
<UnhealthyFlagBox flagCount={staleFlags.total} />
<TextContainer>
<Typography variant='body2'>
To keep your project healthy, archive stale feature
flags and remove code from your code base to reduce
technical debt.
</Typography>
<Link to={`/projects/${projectId}?state=IS%3Astale`}>
View unhealthy flags
</Link>
</TextContainer>
</ChartRow>
</Wrapper>
);
};