2024-01-30 17:02:13 +01:00
|
|
|
import { useMemo, VFC } from 'react';
|
|
|
|
import {
|
|
|
|
Box,
|
|
|
|
styled,
|
|
|
|
Typography,
|
|
|
|
useMediaQuery,
|
|
|
|
useTheme,
|
|
|
|
} from '@mui/material';
|
2024-01-22 11:07:38 +01:00
|
|
|
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
|
|
|
import { UsersChart } from './UsersChart/UsersChart';
|
2024-01-22 12:15:49 +01:00
|
|
|
import { FlagsChart } from './FlagsChart/FlagsChart';
|
2024-01-26 09:03:12 +01:00
|
|
|
import { useExecutiveDashboard } from 'hooks/api/getters/useExecutiveSummary/useExecutiveSummary';
|
2024-01-25 14:43:59 +01:00
|
|
|
import { UserStats } from './UserStats/UserStats';
|
2024-01-26 14:22:16 +01:00
|
|
|
import { FlagStats } from './FlagStats/FlagStats';
|
2024-01-30 17:02:13 +01:00
|
|
|
import { Widget } from './Widget/Widget';
|
2024-01-31 08:48:10 +01:00
|
|
|
import { FlagsProjectChart } from './FlagsProjectChart/FlagsProjectChart';
|
2024-01-31 13:19:28 +01:00
|
|
|
import { ProjectHealthChart } from './ProjectHealthChart/ProjectHealthChart';
|
2024-02-01 12:22:27 +01:00
|
|
|
import { TimeToProductionChart } from './TimeToProductionChart/TimeToProductionChart';
|
2024-01-22 11:07:38 +01:00
|
|
|
|
|
|
|
const StyledGrid = styled(Box)(({ theme }) => ({
|
|
|
|
display: 'grid',
|
2024-01-26 14:33:11 +01:00
|
|
|
gridTemplateColumns: `300px 1fr`,
|
2024-01-30 09:00:06 +01:00
|
|
|
gridAutoRows: 'auto',
|
2024-01-22 11:07:38 +01:00
|
|
|
gap: theme.spacing(2),
|
|
|
|
}));
|
2024-01-18 12:32:25 +01:00
|
|
|
|
2024-01-30 17:02:13 +01:00
|
|
|
const useDashboardGrid = () => {
|
|
|
|
const theme = useTheme();
|
|
|
|
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
|
|
|
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
|
|
|
|
|
|
|
if (isSmallScreen) {
|
|
|
|
return {
|
|
|
|
gridTemplateColumns: `1fr`,
|
|
|
|
chartSpan: 1,
|
|
|
|
userTrendsOrder: 3,
|
|
|
|
flagStatsOrder: 2,
|
2024-01-31 10:50:50 +01:00
|
|
|
largeChartSpan: 1,
|
2024-01-30 17:02:13 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isMediumScreen) {
|
|
|
|
return {
|
|
|
|
gridTemplateColumns: `1fr 1fr`,
|
|
|
|
chartSpan: 2,
|
|
|
|
userTrendsOrder: 3,
|
|
|
|
flagStatsOrder: 2,
|
2024-01-31 10:50:50 +01:00
|
|
|
largeChartSpan: 2,
|
2024-01-30 17:02:13 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
gridTemplateColumns: `300px auto`,
|
|
|
|
chartSpan: 1,
|
|
|
|
userTrendsOrder: 2,
|
|
|
|
flagStatsOrder: 3,
|
2024-01-31 10:50:50 +01:00
|
|
|
largeChartSpan: 2,
|
2024-01-30 17:02:13 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-01-18 12:32:25 +01:00
|
|
|
export const ExecutiveDashboard: VFC = () => {
|
2024-01-26 09:03:12 +01:00
|
|
|
const { executiveDashboardData, loading, error } = useExecutiveDashboard();
|
|
|
|
|
2024-01-30 17:02:13 +01:00
|
|
|
const flagPerUsers = useMemo(() => {
|
2024-01-30 10:07:16 +01:00
|
|
|
if (
|
|
|
|
executiveDashboardData.users.total === 0 ||
|
|
|
|
executiveDashboardData.flags.total === 0
|
|
|
|
)
|
|
|
|
return '0';
|
|
|
|
|
|
|
|
return (
|
|
|
|
executiveDashboardData.flags.total /
|
|
|
|
executiveDashboardData.users.total
|
|
|
|
).toFixed(1);
|
2024-01-30 17:02:13 +01:00
|
|
|
}, [executiveDashboardData]);
|
|
|
|
|
2024-01-31 10:50:50 +01:00
|
|
|
const {
|
|
|
|
gridTemplateColumns,
|
|
|
|
chartSpan,
|
|
|
|
userTrendsOrder,
|
|
|
|
flagStatsOrder,
|
|
|
|
largeChartSpan,
|
|
|
|
} = useDashboardGrid();
|
2024-01-30 10:07:16 +01:00
|
|
|
|
2024-01-22 11:07:38 +01:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Box sx={(theme) => ({ paddingBottom: theme.spacing(4) })}>
|
|
|
|
<PageHeader
|
|
|
|
titleElement={
|
2024-01-31 10:07:29 +01:00
|
|
|
<Typography variant='h1' component='span'>
|
2024-01-22 11:07:38 +01:00
|
|
|
Dashboard
|
|
|
|
</Typography>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Box>
|
2024-01-30 17:02:13 +01:00
|
|
|
<StyledGrid sx={{ gridTemplateColumns }}>
|
|
|
|
<Widget title='Total users' order={1}>
|
|
|
|
<UserStats count={executiveDashboardData.users.total} />
|
|
|
|
</Widget>
|
|
|
|
<Widget title='Users' order={userTrendsOrder} span={chartSpan}>
|
|
|
|
<UsersChart
|
|
|
|
userTrends={executiveDashboardData.userTrends}
|
|
|
|
/>
|
|
|
|
</Widget>
|
|
|
|
<Widget
|
|
|
|
title='Total flags'
|
|
|
|
tooltip='Total flags represent the total ctive flags (not archived) that currently exist across all projects of your application.'
|
|
|
|
order={flagStatsOrder}
|
|
|
|
>
|
|
|
|
<FlagStats
|
|
|
|
count={executiveDashboardData.flags.total}
|
|
|
|
flagsPerUser={flagPerUsers}
|
|
|
|
/>
|
|
|
|
</Widget>
|
|
|
|
<Widget title='Number of flags' order={4} span={chartSpan}>
|
|
|
|
<FlagsChart
|
|
|
|
flagTrends={executiveDashboardData.flagTrends}
|
|
|
|
/>
|
|
|
|
</Widget>
|
2024-01-31 10:50:50 +01:00
|
|
|
<Widget
|
|
|
|
title='Number of flags per project'
|
|
|
|
order={5}
|
|
|
|
span={largeChartSpan}
|
|
|
|
>
|
|
|
|
<FlagsProjectChart
|
|
|
|
projectFlagTrends={
|
|
|
|
executiveDashboardData.projectFlagTrends
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Widget>
|
2024-01-31 13:19:28 +01:00
|
|
|
<Widget
|
|
|
|
title='Health per project'
|
|
|
|
order={6}
|
|
|
|
span={largeChartSpan}
|
|
|
|
>
|
|
|
|
<ProjectHealthChart
|
|
|
|
projectFlagTrends={
|
|
|
|
executiveDashboardData.projectFlagTrends
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Widget>
|
2024-02-01 12:22:27 +01:00
|
|
|
<Widget
|
|
|
|
title='Time to production'
|
|
|
|
order={7}
|
|
|
|
span={largeChartSpan}
|
|
|
|
>
|
|
|
|
<TimeToProductionChart
|
|
|
|
projectFlagTrends={
|
|
|
|
executiveDashboardData.projectFlagTrends
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Widget>
|
2024-01-22 11:07:38 +01:00
|
|
|
</StyledGrid>
|
|
|
|
</>
|
|
|
|
);
|
2024-01-18 12:32:25 +01:00
|
|
|
};
|