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> <NarrowContainer>
<FlagTypesUsed featureTypeCounts={data.featureTypeCounts} /> <FlagTypesUsed featureTypeCounts={data.featureTypeCounts} />
</NarrowContainer> </NarrowContainer>
<NarrowContainer> <NarrowContainer sx={{ padding: 0 }}>
<ProjectMembers projectId={projectId} members={data.members} /> <ProjectMembers projectId={projectId} members={data.members} />
</NarrowContainer> </NarrowContainer>
<WideContainer> <WideContainer>

View File

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

View File

@ -2,6 +2,9 @@ import { Box, styled, Typography } from '@mui/material';
import type { ProjectStatsSchema } from 'openapi/models'; import type { ProjectStatsSchema } from 'openapi/models';
import { HelpPopper } from './HelpPopper'; import { HelpPopper } from './HelpPopper';
import { StatusBox } from './StatusBox'; 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 }) => ({ const StyledBox = styled(Box)(({ theme }) => ({
display: 'grid', 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 }) => ({ const StyledTimeToProductionDescription = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize, fontSize: theme.typography.body2.fontSize,
lineHeight: theme.typography.body2.lineHeight, 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 { interface IProjectStatsProps {
stats: ProjectStatsSchema; stats: ProjectStatsSchema;
} }
@ -45,6 +41,7 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
if (Object.keys(stats).length === 0) { if (Object.keys(stats).length === 0) {
return null; return null;
} }
const projectId = useRequiredPathParam('projectId');
const { const {
avgTimeToProdCurrentWindow, avgTimeToProdCurrentWindow,
@ -58,7 +55,6 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
return ( return (
<StyledBox> <StyledBox>
<StyledWidget>
<StatusBox <StatusBox
title='Total changes' title='Total changes'
boxText={String(projectActivityCurrentWindow)} boxText={String(projectActivityCurrentWindow)}
@ -71,8 +67,6 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
project. project.
</HelpPopper> </HelpPopper>
</StatusBox> </StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox <StatusBox
title='Avg. time to production' title='Avg. time to production'
boxText={ boxText={
@ -95,42 +89,43 @@ export const ProjectInsightsStats = ({ stats }: IProjectStatsProps) => {
percentage percentage
> >
<HelpPopper id='avg-time-to-prod'> <HelpPopper id='avg-time-to-prod'>
How long did it take on average from a feature toggle How long did it take on average from a feature toggle was
was created until it was enabled in an environment of created until it was enabled in an environment of type
type production. This is calculated only from feature production. This is calculated only from feature toggles
toggles with the type of "release". with the type of "release".
</HelpPopper> </HelpPopper>
</StatusBox> </StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox <StatusBox
title='Features created' title='Features created'
boxText={String(createdCurrentWindow)} boxText={String(createdCurrentWindow)}
change={createdCurrentWindow - createdPastWindow} change={createdCurrentWindow - createdPastWindow}
/> >
</StyledWidget> <NavigationBar to={`/projects/${projectId}`}>
<KeyboardArrowRight />
</NavigationBar>
</StatusBox>
<StyledWidget>
<StatusBox <StatusBox
title='Stale toggles' title='Stale flags'
boxText={String(projectActivityCurrentWindow)} boxText={String(projectActivityCurrentWindow)}
change={ change={
projectActivityCurrentWindow - projectActivityPastWindow projectActivityCurrentWindow - projectActivityPastWindow
} }
> >
<HelpPopper id='stale-toggles'> <NavigationBar to={`/projects/${projectId}/health`}>
Sum of all stale toggles in the project <KeyboardArrowRight />
</HelpPopper> </NavigationBar>
</StatusBox> </StatusBox>
</StyledWidget>
<StyledWidget>
<StatusBox <StatusBox
title='Features archived' title='Features archived'
boxText={String(archivedCurrentWindow)} boxText={String(archivedCurrentWindow)}
change={archivedCurrentWindow - archivedPastWindow} change={archivedCurrentWindow - archivedPastWindow}
/> >
</StyledWidget> <NavigationBar to={`/projects/${projectId}/archive`}>
<KeyboardArrowRight />
</NavigationBar>
</StatusBox>
</StyledBox> </StyledBox>
); );
}; };

View File

@ -5,10 +5,6 @@ import { Box, Typography, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { flexRow } from 'themes/themeStyles'; import { flexRow } from 'themes/themeStyles';
const StyledTypographyHeader = styled(Typography)(({ theme }) => ({
marginBottom: theme.spacing(2.5),
}));
const StyledTypographyCount = styled(Box)(({ theme }) => ({ const StyledTypographyCount = styled(Box)(({ theme }) => ({
fontSize: theme.fontSizes.largeHeader, fontSize: theme.fontSizes.largeHeader,
})); }));
@ -31,8 +27,25 @@ const StyledTypographyChange = styled(Typography)(({ theme }) => ({
fontWeight: theme.typography.fontWeightBold, 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 { interface IStatusBoxProps {
title?: string; title: string;
boxText: ReactNode; boxText: ReactNode;
change?: number; change?: number;
percentage?: boolean; percentage?: boolean;
@ -42,10 +55,24 @@ interface IStatusBoxProps {
const resolveIcon = (change: number) => { const resolveIcon = (change: number) => {
if (change > 0) { if (change > 0) {
return ( 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) => { const resolveColor = (change: number) => {
@ -63,23 +90,14 @@ export const StatusBox: FC<IStatusBoxProps> = ({
children, children,
customChangeElement, customChangeElement,
}) => ( }) => (
<> <StyledWidget>
<ConditionallyRender <RowContainer>
condition={Boolean(title)} <Typography variant='h3' data-loading>
show={
<StyledTypographyHeader data-loading>
{title} {title}
</StyledTypographyHeader> </Typography>
}
/>
{children} {children}
<Box </RowContainer>
sx={{ <RowContainer>
...flexRow,
justifyContent: 'center',
width: 'auto',
}}
>
<StyledTypographyCount data-loading> <StyledTypographyCount data-loading>
{boxText} {boxText}
</StyledTypographyCount> </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 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 { StatusBox } from '../ProjectInsightsStats/StatusBox';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -11,18 +11,13 @@ interface IProjectMembersProps {
} }
const NavigationBar = styled(Link)(({ theme }) => ({ const NavigationBar = styled(Link)(({ theme }) => ({
marginLeft: 'auto',
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
textDecoration: 'none', textDecoration: 'none',
color: theme.palette.text.primary, color: theme.palette.text.primary,
})); }));
export const StyledProjectInfoWidgetContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2.5),
}));
export const ProjectMembers = ({ export const ProjectMembers = ({
members, members,
projectId, projectId,
@ -35,18 +30,14 @@ export const ProjectMembers = ({
const { currentMembers, change } = members; const { currentMembers, change } = members;
return ( return (
<StyledProjectInfoWidgetContainer> <StatusBox
title={'Project members'}
boxText={`${currentMembers}`}
change={change}
>
<NavigationBar to={link}> <NavigationBar to={link}>
<Typography variant='h3'>Project members</Typography>
<KeyboardArrowRight /> <KeyboardArrowRight />
</NavigationBar> </NavigationBar>
<Box </StatusBox>
sx={{
display: 'flex',
}}
>
<StatusBox boxText={`${currentMembers}`} change={change} />
</Box>
</StyledProjectInfoWidgetContainer>
); );
}; };