1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

refactor: fix stats layout and unify components (#6671)

This commit is contained in:
Jaanus Sellin 2024-03-22 10:07:44 +02:00 committed by GitHub
parent e6150def36
commit f5a7cc9125
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 135 additions and 137 deletions

View File

@ -57,7 +57,7 @@ export const ProjectInsights = () => {
<NarrowContainer>
<FlagTypesUsed featureTypeCounts={data.featureTypeCounts} />
</NarrowContainer>
<NarrowContainer>
<NarrowContainer sx={{ padding: 0 }}>
<ProjectMembers projectId={projectId} members={data.members} />
</NarrowContainer>
<WideContainer>

View File

@ -34,13 +34,7 @@ export const HelpPopper: FC<IHelpPopperProps> = ({ children, id }) => {
const open = Boolean(anchor);
return (
<Box
sx={{
position: 'absolute',
top: (theme) => theme.spacing(0.5),
right: (theme) => theme.spacing(0.5),
}}
>
<Box>
<IconButton onClick={onOpen} aria-describedby={id} size='small'>
<HelpOutline
sx={{

View File

@ -2,6 +2,9 @@ import { Box, styled, Typography } from '@mui/material';
import type { ProjectStatsSchema } from 'openapi/models';
import { HelpPopper } from './HelpPopper';
import { StatusBox } from './StatusBox';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import { Link } from 'react-router-dom';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
const StyledBox = styled(Box)(({ theme }) => ({
display: 'grid',
@ -16,27 +19,20 @@ const StyledBox = styled(Box)(({ theme }) => ({
},
}));
const StyledWidget = styled(Box)(({ theme }) => ({
position: 'relative',
padding: theme.spacing(3),
backgroundColor: theme.palette.background.paper,
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: `${theme.shape.borderRadiusLarge}px`,
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(2),
},
}));
const StyledTimeToProductionDescription = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize,
lineHeight: theme.typography.body2.lineHeight,
}));
const NavigationBar = styled(Link)(({ theme }) => ({
marginLeft: 'auto',
display: 'flex',
justifyContent: 'space-between',
textDecoration: 'none',
color: theme.palette.text.primary,
}));
interface IProjectStatsProps {
stats: ProjectStatsSchema;
}
@ -45,6 +41,7 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
if (Object.keys(stats).length === 0) {
return null;
}
const projectId = useRequiredPathParam('projectId');
const {
avgTimeToProdCurrentWindow,
@ -58,7 +55,6 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
return (
<StyledBox>
<StyledWidget>
<StatusBox
title='Total changes'
boxText={String(projectActivityCurrentWindow)}
@ -71,8 +67,6 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
project.
</HelpPopper>
</StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox
title='Avg. time to production'
boxText={
@ -95,42 +89,43 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
percentage
>
<HelpPopper id='avg-time-to-prod'>
How long did it take on average from a feature toggle
was created until it was enabled in an environment of
type production. This is calculated only from feature
toggles with the type of "release".
How long did it take on average from a feature toggle was
created until it was enabled in an environment of type
production. This is calculated only from feature toggles
with the type of "release".
</HelpPopper>
</StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox
title='Features created'
boxText={String(createdCurrentWindow)}
change={createdCurrentWindow - createdPastWindow}
/>
</StyledWidget>
>
<NavigationBar to={`/projects/${projectId}`}>
<KeyboardArrowRight />
</NavigationBar>
</StatusBox>
<StyledWidget>
<StatusBox
title='Stale toggles'
title='Stale flags'
boxText={String(projectActivityCurrentWindow)}
change={
projectActivityCurrentWindow - projectActivityPastWindow
}
>
<HelpPopper id='stale-toggles'>
Sum of all stale toggles in the project
</HelpPopper>
<NavigationBar to={`/projects/${projectId}/health`}>
<KeyboardArrowRight />
</NavigationBar>
</StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox
title='Features archived'
boxText={String(archivedCurrentWindow)}
change={archivedCurrentWindow - archivedPastWindow}
/>
</StyledWidget>
>
<NavigationBar to={`/projects/${projectId}/archive`}>
<KeyboardArrowRight />
</NavigationBar>
</StatusBox>
</StyledBox>
);
};

View File

@ -5,10 +5,6 @@ import { Box, Typography, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { flexRow } from 'themes/themeStyles';
const StyledTypographyHeader = styled(Typography)(({ theme }) => ({
marginBottom: theme.spacing(2.5),
}));
const StyledTypographyCount = styled(Box)(({ theme }) => ({
fontSize: theme.fontSizes.largeHeader,
}));
@ -31,8 +27,25 @@ const StyledTypographyChange = styled(Typography)(({ theme }) => ({
fontWeight: theme.typography.fontWeightBold,
}));
const RowContainer = styled(Box)(({ theme }) => ({
...flexRow,
}));
const StyledWidget = styled(Box)(({ theme }) => ({
padding: theme.spacing(3),
backgroundColor: theme.palette.background.paper,
flex: 1,
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2.5),
borderRadius: `${theme.shape.borderRadiusLarge}px`,
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(2),
},
}));
interface IStatusBoxProps {
title?: string;
title: string;
boxText: ReactNode;
change?: number;
percentage?: boolean;
@ -42,10 +55,24 @@ interface IStatusBoxProps {
const resolveIcon = (change: number) => {
if (change > 0) {
return (
<CallMade sx={{ color: 'success.dark', height: 20, width: 20 }} />
<CallMade
sx={{
color: 'success.dark',
height: 20,
width: 20,
}}
/>
);
}
return <SouthEast sx={{ color: 'warning.dark', height: 20, width: 20 }} />;
return (
<SouthEast
sx={{
color: 'warning.dark',
height: 20,
width: 20,
}}
/>
);
};
const resolveColor = (change: number) => {
@ -63,23 +90,14 @@ export const StatusBox: FC<IStatusBoxProps> = ({
children,
customChangeElement,
}) => (
<>
<ConditionallyRender
condition={Boolean(title)}
show={
<StyledTypographyHeader data-loading>
<StyledWidget>
<RowContainer>
<Typography variant='h3' data-loading>
{title}
</StyledTypographyHeader>
}
/>
</Typography>
{children}
<Box
sx={{
...flexRow,
justifyContent: 'center',
width: 'auto',
}}
>
</RowContainer>
<RowContainer>
<StyledTypographyCount data-loading>
{boxText}
</StyledTypographyCount>
@ -124,6 +142,6 @@ export const StatusBox: FC<IStatusBoxProps> = ({
/>
}
/>
</Box>
</>
</RowContainer>
</StyledWidget>
);

View File

@ -1,5 +1,5 @@
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { Box, styled, Typography } from '@mui/material';
import { styled } from '@mui/material';
import { StatusBox } from '../ProjectInsightsStats/StatusBox';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import { Link } from 'react-router-dom';
@ -11,18 +11,13 @@ interface IProjectMembersProps {
}
const NavigationBar = styled(Link)(({ theme }) => ({
marginLeft: 'auto',
display: 'flex',
justifyContent: 'space-between',
textDecoration: 'none',
color: theme.palette.text.primary,
}));
export const StyledProjectInfoWidgetContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2.5),
}));
export const ProjectMembers = ({
members,
projectId,
@ -35,18 +30,14 @@ export const ProjectMembers = ({
const { currentMembers, change } = members;
return (
<StyledProjectInfoWidgetContainer>
<StatusBox
title={'Project members'}
boxText={`${currentMembers}`}
change={change}
>
<NavigationBar to={link}>
<Typography variant='h3'>Project members</Typography>
<KeyboardArrowRight />
</NavigationBar>
<Box
sx={{
display: 'flex',
}}
>
<StatusBox boxText={`${currentMembers}`} change={change} />
</Box>
</StyledProjectInfoWidgetContainer>
</StatusBox>
);
};