From fb9c754008aecc76a3c9b1618101ee718ba9f331 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Mon, 18 Nov 2024 12:01:08 +0100 Subject: [PATCH] feat: combine health and status widgets (#8782) This PR combines the health and status widgets into a single widget. It adds a new row with information on your unhealthy flags. The stat prettifies large numbers to avoid overflows for very large numbers. To keep it in line with the SVG, I've extracted some of the constants so we can share them for size calculation. ![image](https://github.com/user-attachments/assets/0b66b6ba-b88c-412e-838f-bd5e7867cdc3) When it folds, it uses the "space-around" algorithm to make the two stats occupy their own positions: ![image](https://github.com/user-attachments/assets/eb3a4f0e-31fa-4895-ba12-c6f910112204) The number uses a custom background color in dark mode because elevation 1 and 2 are the same there: ![image](https://github.com/user-attachments/assets/fa405c33-f38a-4fea-bf20-e1d9bf21bb1c) --- .../Project/ProjectStatus/ProjectHealth.tsx | 96 ++++++++++++++++--- .../ProjectHealthGrid.styles.tsx | 2 +- .../ProjectStatus/ProjectHealthGrid.tsx | 6 +- .../Project/ProjectStatus/StaleFlags.tsx | 53 ---------- 4 files changed, 85 insertions(+), 72 deletions(-) delete mode 100644 frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx index 20bcd9174f..efe6d7304d 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectHealth.tsx @@ -4,6 +4,12 @@ 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', @@ -13,14 +19,14 @@ const TextContainer = styled('div')(({ theme }) => ({ const ChartRow = styled('div')(({ theme }) => ({ display: 'flex', - alignItems: 'center', + alignItems: 'flex-start', gap: theme.spacing(2), })); const SVGWrapper = styled('div')(({ theme }) => ({ flex: 'none', height: 85, - width: 100, + width: ChartContainerWidth, position: 'relative', })); @@ -28,16 +34,67 @@ 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 ( + + + + + + unhealthy + {flagWord} + + + ); +}; + +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 }, + data: { averageHealth, staleFlags }, } = useProjectStatus(projectId); const { isOss } = useUiConfig(); const theme = useTheme(); - const radius = 40; - const strokeWidth = 13; - const circumference = 2 * Math.PI * radius; + const circumference = 2 * Math.PI * ChartRadius; // const gapLength = 0.3; const filledLength = 1 - gapLength; @@ -52,27 +109,27 @@ export const ProjectHealth = () => { : theme.palette.success.border; return ( - + @@ -82,7 +139,7 @@ export const ProjectHealth = () => { textAnchor='middle' dominantBaseline='middle' fill={theme.palette.text.primary} - fontSize='24px' + fontSize={theme.typography.h1.fontSize} > {averageHealth}% @@ -100,6 +157,19 @@ export const ProjectHealth = () => { )} - + + + + + To keep your project healthy, archive stale feature + flags and remove code from your code base to reduce + technical debt. + + + View unhealthy flags + + + + ); }; diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx index 1cc5e10e43..709e354ab3 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx @@ -1,7 +1,7 @@ import { styled } from '@mui/material'; export const HealthGridTile = styled('article')(({ theme }) => ({ - backgroundColor: theme.palette.neutral.light, + backgroundColor: theme.palette.background.elevation1, padding: theme.spacing(3), borderRadius: theme.shape.borderRadiusExtraLarge, })); diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx index bc6517a306..85db818ca4 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx @@ -1,6 +1,5 @@ import { ProjectHealth } from './ProjectHealth'; import { styled } from '@mui/material'; -import { StaleFlags } from './StaleFlags'; import { ProjectResources } from './ProjectResources'; const onNarrowGrid = (css: object) => ({ @@ -18,7 +17,7 @@ const HealthGrid = styled('div')(({ theme }) => ({ display: 'grid', gridTemplateAreas: ` "health resources" - "stale resources" + "health resources" `, gridTemplateColumns: 'repeat(2, minmax(300px, 1fr))', gap: theme.spacing(1, 2), @@ -45,9 +44,6 @@ export const ProjectHealthGrid = () => { - - - diff --git a/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx b/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx deleted file mode 100644 index 8c533f45f0..0000000000 --- a/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Typography } from '@mui/material'; -import { styled } from '@mui/material'; -import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber'; -import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus'; -import useLoading from 'hooks/useLoading'; -import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; -import type { FC } from 'react'; -import { Link } from 'react-router-dom'; -import { HealthGridTile } from './ProjectHealthGrid.styles'; - -const Wrapper = styled(HealthGridTile)(({ theme }) => ({ - 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 ( - - - - ); -}; - -export const StaleFlags = () => { - const projectId = useRequiredPathParam('projectId'); - const { data, loading } = useProjectStatus(projectId); - const loadingRef = useLoading(loading, '[data-loading-stale-flags=true]'); - - return ( - - - {' '} - - stale flags - - - - Remember to archive your stale feature flags to keep the project - healthy - - - ); -};