mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: project members widget (#6628)
![image](https://github.com/Unleash/unleash/assets/964450/7e27dbab-da24-44b2-8336-36df9660bd78)
This commit is contained in:
parent
f0e5d075a7
commit
1becfc0202
@ -13,6 +13,9 @@ interface IProjectMembersWidgetProps {
|
|||||||
change?: number;
|
change?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in favor of ProjectMembers.tsx
|
||||||
|
*/
|
||||||
export const ProjectMembersWidget = ({
|
export const ProjectMembersWidget = ({
|
||||||
projectId,
|
projectId,
|
||||||
memberCount,
|
memberCount,
|
||||||
|
@ -7,6 +7,7 @@ import { ProjectInsightsStats } from './ProjectInsightsStats/ProjectInsightsStat
|
|||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { useProjectInsights } from 'hooks/api/getters/useProjectInsights/useProjectInsights';
|
import { useProjectInsights } from 'hooks/api/getters/useProjectInsights/useProjectInsights';
|
||||||
import useLoading from 'hooks/useLoading';
|
import useLoading from 'hooks/useLoading';
|
||||||
|
import { ProjectMembers } from './ProjectMembers/ProjectMembers';
|
||||||
|
|
||||||
const Container = styled(Box)(({ theme }) => ({
|
const Container = styled(Box)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
@ -56,7 +57,9 @@ export const ProjectInsights = () => {
|
|||||||
<NarrowContainer>
|
<NarrowContainer>
|
||||||
<FlagTypesUsed featureTypeCounts={data.featureTypeCounts} />
|
<FlagTypesUsed featureTypeCounts={data.featureTypeCounts} />
|
||||||
</NarrowContainer>
|
</NarrowContainer>
|
||||||
<NarrowContainer>Project members</NarrowContainer>
|
<NarrowContainer>
|
||||||
|
<ProjectMembers projectId={projectId} members={data.members} />
|
||||||
|
</NarrowContainer>
|
||||||
<WideContainer>
|
<WideContainer>
|
||||||
{data.changeRequests && (
|
{data.changeRequests && (
|
||||||
<ChangeRequests changeRequests={data.changeRequests} />
|
<ChangeRequests changeRequests={data.changeRequests} />
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import { render } from 'utils/testRenderer';
|
||||||
|
import { ProjectMembers } from './ProjectMembers';
|
||||||
|
|
||||||
|
test('Show outdated project members', async () => {
|
||||||
|
const members = {
|
||||||
|
active: 10,
|
||||||
|
totalPreviousMonth: 2,
|
||||||
|
inactive: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<ProjectMembers projectId={'default'} members={members} />);
|
||||||
|
|
||||||
|
await screen.findByText('15');
|
||||||
|
await screen.findByText('+13');
|
||||||
|
await screen.findByText('10');
|
||||||
|
await screen.findByText('5');
|
||||||
|
});
|
@ -0,0 +1,149 @@
|
|||||||
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import { Box, styled, Typography, useTheme } from '@mui/material';
|
||||||
|
import { StatusBox } from '../ProjectInsightsStats/StatusBox';
|
||||||
|
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import type { ProjectInsightsSchemaMembers } from '../../../../../openapi';
|
||||||
|
|
||||||
|
interface IProjectMembersProps {
|
||||||
|
members: ProjectInsightsSchemaMembers;
|
||||||
|
projectId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NavigationBar = styled(Link)(({ theme }) => ({
|
||||||
|
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 BarContainer = styled('div')(({ theme }) => ({
|
||||||
|
width: '100%',
|
||||||
|
height: '20px',
|
||||||
|
display: 'flex',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ActiveBar = styled('span', {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'percentage',
|
||||||
|
})<{
|
||||||
|
percentage: number;
|
||||||
|
}>(({ theme, percentage }) => ({
|
||||||
|
width: `${percentage - 1}%`,
|
||||||
|
backgroundColor: theme.palette.success.border,
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const InactiveBar = styled('span', {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'percentage',
|
||||||
|
})<{
|
||||||
|
percentage: number;
|
||||||
|
}>(({ theme, percentage }) => ({
|
||||||
|
width: `${percentage - 1}%`,
|
||||||
|
backgroundColor: theme.palette.warning.border,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const CountContainer = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: theme.spacing(1.5),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const CountRow = styled(NavigationBar)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
padding: theme.spacing(0.5, 1, 0, 2),
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: theme.spacing(3),
|
||||||
|
alignSelf: 'stretch',
|
||||||
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
|
background: '#F7F7FA',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusWithDot = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Dot = styled('span', {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'color',
|
||||||
|
})<{
|
||||||
|
color?: string;
|
||||||
|
}>(({ theme, color }) => ({
|
||||||
|
height: '15px',
|
||||||
|
width: '15px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'inline-block',
|
||||||
|
backgroundColor: color,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const StyledCount = styled('span')(({ theme }) => ({
|
||||||
|
fontSize: theme.typography.h1.fontSize,
|
||||||
|
fontWeight: theme.typography.fontWeightRegular,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const ProjectMembers = ({
|
||||||
|
members,
|
||||||
|
projectId,
|
||||||
|
}: IProjectMembersProps) => {
|
||||||
|
const { uiConfig } = useUiConfig();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const link = uiConfig?.versionInfo?.current?.enterprise
|
||||||
|
? `/projects/${projectId}/settings/access`
|
||||||
|
: `/admin/users`;
|
||||||
|
|
||||||
|
const { active, totalPreviousMonth, inactive } = members;
|
||||||
|
|
||||||
|
const currentMembers = active + inactive;
|
||||||
|
const change = currentMembers - (totalPreviousMonth || 0);
|
||||||
|
|
||||||
|
const activePercentage = (active / currentMembers) * 100;
|
||||||
|
const inactivePercentage = (inactive / currentMembers) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledProjectInfoWidgetContainer>
|
||||||
|
<NavigationBar to={link}>
|
||||||
|
<Typography variant='h3'>Project members</Typography>
|
||||||
|
<KeyboardArrowRight />
|
||||||
|
</NavigationBar>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StatusBox boxText={`${currentMembers}`} change={change} />
|
||||||
|
</Box>
|
||||||
|
<BarContainer>
|
||||||
|
<ActiveBar percentage={activePercentage} />
|
||||||
|
<InactiveBar percentage={inactivePercentage} />
|
||||||
|
</BarContainer>
|
||||||
|
<CountContainer>
|
||||||
|
<CountRow to={link}>
|
||||||
|
<StatusWithDot>
|
||||||
|
<Dot color={theme.palette.success.border} />
|
||||||
|
<Box>Active</Box>
|
||||||
|
<StyledCount>{active}</StyledCount>
|
||||||
|
</StatusWithDot>
|
||||||
|
<KeyboardArrowRight />
|
||||||
|
</CountRow>
|
||||||
|
<CountRow to={link}>
|
||||||
|
<StatusWithDot>
|
||||||
|
<Dot color={theme.palette.warning.border} />
|
||||||
|
<Box>Inactive</Box>
|
||||||
|
<StyledCount>{inactive}</StyledCount>
|
||||||
|
</StatusWithDot>
|
||||||
|
<KeyboardArrowRight />
|
||||||
|
</CountRow>
|
||||||
|
</CountContainer>
|
||||||
|
</StyledProjectInfoWidgetContainer>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user