Skip to content

Commit

Permalink
feat: Add stale flags counter (#8741)
Browse files Browse the repository at this point in the history
This PR adds the stale flag component to the health grid. In doing so,
it also reworks the layout of the health row (now a grid) and updates
the health component.

In addition to removing the text from the component, I have adjust the
SVG a bit to make it not shrink on smaller screens and have adjusted
it's spacing, so that it's not full of dead space at the bottom. This
makes it easier to style because it doesn't add 15px of invisible
content.

This PR also touches up a few other visual issues I found, such as
header level and sidebar width.

Wide:

![image](https://github.com/user-attachments/assets/acb57b17-eb7f-4b69-9bfa-1113bb748467)

Medium:

![image](https://github.com/user-attachments/assets/a57331b0-825f-4b20-9b05-3ecd81804f5d)

Narrow:

![image](https://github.com/user-attachments/assets/65c6e8d1-1783-4354-b71b-2867eabcc9ec)
  • Loading branch information
thomasheartman authored Nov 14, 2024
1 parent 3e424ec commit 9440b52
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 67 deletions.
112 changes: 64 additions & 48 deletions frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useTheme, Typography } from '@mui/material';
import { styled } from '@mui/system';
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';
Expand All @@ -10,21 +9,34 @@ const HealthContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(3),
borderRadius: theme.shape.borderRadiusExtraLarge,
minWidth: '300px',
gridArea: 'health',
}));

const TextContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}));

const ChartRow = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(2),
}));

const SVGWrapper = styled('div')(({ theme }) => ({
flex: 'none',
height: 85,
width: 100,
position: 'relative',
}));

const StyledSVG = styled('svg')({
width: 200,
height: 100,
position: 'absolute',
});

const DescriptionText = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
marginBottom: theme.spacing(2),
const StyledLink = styled(Link)(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
}));

export const ProjectHealth = () => {
Expand Down Expand Up @@ -53,48 +65,52 @@ export const ProjectHealth = () => {
return (
<HealthContainer>
<ChartRow>
<StyledSVG viewBox='0 0 100 100'>
<circle
cx='50'
cy='50'
r={radius}
fill='none'
stroke={theme.palette.grey[300]}
strokeWidth={strokeWidth}
strokeDasharray={`${filledLength * circumference} ${gapLength * circumference}`}
strokeDashoffset={offset * circumference}
/>
<circle
cx='50'
cy='50'
r={radius}
fill='none'
stroke={healthColor}
strokeWidth={strokeWidth}
strokeDasharray={`${healthLength} ${circumference - healthLength}`}
strokeDashoffset={offset * circumference}
/>
<text
x='50'
y='50'
textAnchor='middle'
dominantBaseline='middle'
fill={theme.palette.text.primary}
fontSize='24px'
>
{averageHealth}%
</text>
</StyledSVG>
<Typography variant='body2'>
On average, your project health has remained at{' '}
{averageHealth}% the last 4 weeks
</Typography>
<SVGWrapper>
<StyledSVG viewBox='0 0 100 100'>
<circle
cx='50'
cy='50'
r={radius}
fill='none'
stroke={theme.palette.grey[300]}
strokeWidth={strokeWidth}
strokeDasharray={`${filledLength * circumference} ${gapLength * circumference}`}
strokeDashoffset={offset * circumference}
/>
<circle
cx='50'
cy='50'
r={radius}
fill='none'
stroke={healthColor}
strokeWidth={strokeWidth}
strokeDasharray={`${healthLength} ${circumference - healthLength}`}
strokeDashoffset={offset * circumference}
/>
<text
x='50'
y='50'
textAnchor='middle'
dominantBaseline='middle'
fill={theme.palette.text.primary}
fontSize='24px'
>
{averageHealth}%
</text>
</StyledSVG>
</SVGWrapper>
<TextContainer>
<Typography variant='body2'>
On average, your project health has remained at{' '}
{averageHealth}% the last 4 weeks
</Typography>
{!isOss() && (
<StyledLink to='/insights'>
View health over time
</StyledLink>
)}
</TextContainer>
</ChartRow>
<DescriptionText variant='body2'>
Remember to archive your stale feature flags to keep the project
health growing
</DescriptionText>
{!isOss() && <Link to='/insights'>View health over time</Link>}
</HealthContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Wrapper = styled('article')(({ theme }) => ({
padding: theme.spacing(3),
borderRadius: theme.shape.borderRadiusExtraLarge,
minWidth: '300px',
gridArea: 'resources',
}));

const ProjectResourcesInner = styled('div')(({ theme }) => ({
Expand All @@ -33,9 +34,9 @@ const ItemContent = styled('span')(({ theme }) => ({
}));

const onNarrowWidget = (css: object) => ({
'@container (max-width: 400px)': css,
'@container (max-width: 385px)': css,
'@supports not (container-type: inline-size)': {
'@media (max-width: 400px)': css,
'@media (max-width: 385px)': css,
},
});

Expand Down Expand Up @@ -116,8 +117,8 @@ export const ProjectResources = () => {
return (
<Wrapper ref={loadingRef}>
<ProjectResourcesInner>
<Typography variant='h3' sx={{ margin: 0 }}>
Project Resources
<Typography variant='h4' sx={{ margin: 0 }}>
Project resources
</Typography>
<ResourceList>
<ListItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { ProjectResources } from './ProjectResources';
import { ProjectActivity } from './ProjectActivity';
import { ProjectHealth } from './ProjectHealth';
import { ProjectLifecycleSummary } from './ProjectLifecycleSummary';
import { StaleFlags } from './StaleFlags';

const ModalContentContainer = styled('div')(({ theme }) => ({
const ModalContentContainer = styled('section')(({ theme }) => ({
minHeight: '100vh',
maxWidth: 1100,
width: '95vw',
backgroundColor: theme.palette.background.default,
padding: theme.spacing(4),
display: 'flex',
Expand All @@ -19,27 +22,43 @@ type Props = {
close: () => void;
};

const HealthRow = styled('div')(({ theme }) => ({
display: 'flex',
flexFlow: 'row wrap',
padding: theme.spacing(2),
gap: theme.spacing(2),
'&>*': {
// todo: reconsider this value when the health widget is
// implemented. It may not be right, but it works for the
// placeholder
flex: '30%',
const onNarrowGrid = (css: object) => ({
'@container (max-width: 650px)': css,
'@supports not (container-type: inline-size)': {
'@media (max-width: 712px)': css,
},
});

const HealthContainer = styled('div')({
containerType: 'inline-size',
});

const HealthGrid = styled('div')(({ theme }) => ({
display: 'grid',
gridTemplateAreas: `
"health resources"
"stale resources"
`,
gridTemplateColumns: '1fr 1fr',
gap: theme.spacing(1, 2),
...onNarrowGrid({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}),
}));

export const ProjectStatusModal = ({ open, close }: Props) => {
return (
<DynamicSidebarModal open={open} onClose={close} label='Project status'>
<ModalContentContainer>
<HealthRow>
<ProjectHealth />
<ProjectResources />
</HealthRow>
<HealthContainer>
<HealthGrid>
<ProjectHealth />
<StaleFlags />
<ProjectResources />
</HealthGrid>
</HealthContainer>

<ProjectActivity />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Typography } from '@mui/material';
import { styled } from '@mui/material';
import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import type { FC } from 'react';
import { Link } from 'react-router-dom';

const Wrapper = styled('article')(({ theme }) => ({
backgroundColor: theme.palette.envAccordion.expanded,
padding: theme.spacing(3),
borderRadius: theme.shape.borderRadiusExtraLarge,
minWidth: '300px',
gridArea: 'stale',
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}));

const BigText = styled('span')(({ theme }) => ({
fontSize: `calc(2 * ${theme.typography.body1.fontSize})`,
lineHeight: 0,
}));

const BigNumber: FC<{ value?: number }> = ({ value }) => {
return (
<BigText>
<PrettifyLargeNumber
value={value ?? 0}
threshold={1000}
precision={1}
/>
</BigText>
);
};

export const StaleFlags = () => {
const projectId = useRequiredPathParam('projectId');
return (
<Wrapper>
<Typography component='h4'>
<BigNumber value={6} />{' '}
<Link to={`/projects/${projectId}?state=IS%3Astale`}>
stale flags
</Link>
</Typography>
<Typography variant='body2'>
Remember to archive your stale feature flags to keep the project
healthy
</Typography>
</Wrapper>
);
};

0 comments on commit 9440b52

Please sign in to comment.