diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts index 1f326346aa..7723163dcb 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.styles.ts @@ -53,8 +53,8 @@ export const StyledWidgetTitle = styled('p')(({ theme }) => ({ export const StyledParagraphGridRow = styled('div')(({ theme }) => ({ display: 'grid', - gridGap: theme.spacing(1), - gridTemplateColumns: `${theme.spacing(1.25)} auto auto`, + gridGap: theme.spacing(1.5), + gridTemplateColumns: `${theme.spacing(1.25)} auto auto`, //20px auto auto margin: theme.spacing(1, 0, 1, 0), fontSize: theme.fontSizes.smallBody, color: theme.palette.text.secondary, diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx index ddbc3e349f..a905c5c297 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectInfo.tsx @@ -7,6 +7,7 @@ import { ToggleTypesWidget } from './ToggleTypesWidget'; import { MetaWidget } from './MetaWidget'; import { ProjectMembersWidget } from './ProjectMembersWidget'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { ProjectStatsSchema } from '@server/openapi'; import { ChangeRequestsWidget } from './ChangeRequestsWidget'; interface IProjectInfoProps { @@ -15,6 +16,7 @@ interface IProjectInfoProps { features: IFeatureToggleListItem[]; health: number; description?: string; + stats: ProjectStatsSchema; } const ProjectInfo = ({ @@ -23,6 +25,7 @@ const ProjectInfo = ({ memberCount, health, features, + stats, }: IProjectInfoProps) => { const { uiConfig, isEnterprise } = useUiConfig(); @@ -52,6 +55,7 @@ const ProjectInfo = ({ } /> diff --git a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx index 3f7489ce28..89db931a6e 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ProjectMembersWidget.tsx @@ -1,21 +1,21 @@ import { - StyledArrowIcon, - StyledProjectInfoWidgetContainer, StyledLink, - StyledParagraphEmphasizedText, - StyledWidgetTitle, + StyledProjectInfoWidgetContainer, StyledSpanLinkText, } from './ProjectInfo.styles'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { StatusBox } from '../ProjectStats/StatusBox'; interface IProjectMembersWidgetProps { projectId: string; memberCount: number; + change?: number; } export const ProjectMembersWidget = ({ projectId, memberCount, + change = 0, }: IProjectMembersWidgetProps) => { const { uiConfig } = useUiConfig(); @@ -26,14 +26,19 @@ export const ProjectMembersWidget = ({ } return ( - - Project members - - {memberCount} - + theme.spacing(0, 0, 3, 0) }} + > + - view more - + + View all members + ); diff --git a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx index 21ab49214b..c0955320a7 100644 --- a/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx +++ b/frontend/src/component/project/Project/ProjectInfo/ToggleTypesWidget.tsx @@ -1,13 +1,14 @@ import { useMemo } from 'react'; -import { styled } from '@mui/material'; +import { styled, SvgIconTypeMap } from '@mui/material'; import type { IFeatureToggleListItem } from 'interfaces/featureToggle'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { StyledCount, - StyledProjectInfoWidgetContainer, StyledParagraphGridRow, + StyledProjectInfoWidgetContainer, StyledWidgetTitle, } from './ProjectInfo.styles'; +import { OverridableComponent } from '@mui/material/OverridableComponent'; export interface IToggleTypesWidgetProps { features: IFeatureToggleListItem[]; @@ -17,74 +18,66 @@ const StyledTypeCount = styled(StyledCount)(() => ({ marginLeft: 'auto', })); -const StyledDiv = styled('div')(({ theme }) => ({ - marginLeft: theme.spacing(1.5), -})); +interface IToggleTypeRowProps { + type: string; + Icon: OverridableComponent; + count: number; +} +const ToggleTypesRow = ({ type, Icon, count }: IToggleTypeRowProps) => { + const getTitleText = (str: string) => { + return str.charAt(0).toUpperCase() + str.slice(1).replace('-', ' '); + }; + return ( + + +
{getTitleText(type)}
+ {count} +
+ ); +}; export const ToggleTypesWidget = ({ features }: IToggleTypesWidgetProps) => { - const { release, experiment, operational, kill, permission } = - useMemo(() => { - const release = - features?.filter(feature => feature.type === 'release') - .length || 0; - const experiment = - features?.filter(feature => feature.type === 'experiment') - .length || 0; - const operational = - features?.filter(feature => feature.type === 'operational') - .length || 0; - const kill = - features?.filter(feature => feature.type === 'kill-switch') - .length || 0; - const permission = - features?.filter(feature => feature.type === 'permission') - .length || 0; + const featureTypeStats = useMemo(() => { + const release = + features?.filter(feature => feature.type === 'release').length || 0; + const experiment = + features?.filter(feature => feature.type === 'experiment').length || + 0; + const operational = + features?.filter(feature => feature.type === 'operational') + .length || 0; + const kill = + features?.filter(feature => feature.type === 'kill-switch') + .length || 0; + const permission = + features?.filter(feature => feature.type === 'permission').length || + 0; - return { - release, - experiment, - operational, - kill, - permission, - }; - }, [features]); - - const ReleaseToggleIcon = getFeatureTypeIcons('release'); - const ExperimentToggleIcon = getFeatureTypeIcons('experiment'); - const OperationalToggleIcon = getFeatureTypeIcons('operational'); - const KillToggleIcon = getFeatureTypeIcons('kill-switch'); - const PermissionToggleIcon = getFeatureTypeIcons('permission'); + return { + release, + experiment, + operational, + 'kill-switch': kill, + permission, + }; + }, [features]); return ( - + theme.spacing(3) }} + > Toggle types used - - - Release - {release} - - - - Experiment - {experiment} - - - - Operational - {operational} - - - - Kill switch - {kill} - - - - Permission - {permission} - + {Object.keys(featureTypeStats).map(type => ( + + ))} ); }; diff --git a/frontend/src/component/project/Project/ProjectOverview.tsx b/frontend/src/component/project/Project/ProjectOverview.tsx index 143687e1b9..8a21f88fc8 100644 --- a/frontend/src/component/project/Project/ProjectOverview.tsx +++ b/frontend/src/component/project/Project/ProjectOverview.tsx @@ -39,7 +39,8 @@ const ProjectOverview = () => { const { project, loading } = useProject(projectId, { refreshInterval, }); - const { members, features, health, description, environments } = project; + const { members, features, health, description, environments, stats } = + project; usePageTitle(`Project overview – ${projectName}`); const { setLastViewed } = useLastViewedProject(); const { uiConfig } = useUiConfig(); @@ -57,6 +58,7 @@ const ProjectOverview = () => { memberCount={members} health={health} features={features} + stats={stats} /> { @@ -81,17 +82,30 @@ export const StatusBox = ({ boxText, change, percentage, + fullWidthBodyText, }: IStatusBoxProps) => { return ( {title} - + {boxText} - + {resolveIcon(change)}