diff --git a/frontend/src/component/insights/InsightsCharts.tsx b/frontend/src/component/insights/InsightsCharts.tsx index da2ff607805d..637bde06d4fb 100644 --- a/frontend/src/component/insights/InsightsCharts.tsx +++ b/frontend/src/component/insights/InsightsCharts.tsx @@ -1,4 +1,6 @@ -import { ConditionallyRender } from '../common/ConditionallyRender/ConditionallyRender'; +import type { VFC } from 'react'; +import { Box, styled } from '@mui/material'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { Widget } from './components/Widget/Widget'; import { UserStats } from './componentsStat/UserStats/UserStats'; import { UsersChart } from './componentsChart/UsersChart/UsersChart'; @@ -18,9 +20,7 @@ import type { InstanceInsightsSchemaUsers, } from 'openapi'; import type { GroupedDataByProject } from './hooks/useGroupedProjectTrends'; -import { Box, styled } from '@mui/material'; -import { allOption } from '../common/ProjectSelect/ProjectSelect'; -import type { VFC } from 'react'; +import { allOption } from 'component/common/ProjectSelect/ProjectSelect'; import { chartInfo } from './chart-info'; interface IChartsProps { @@ -107,6 +107,7 @@ export const InsightsCharts: VFC = ({ count={users.total} active={users.active} inactive={users.inactive} + isLoading={loading} /> } @@ -116,7 +117,10 @@ export const InsightsCharts: VFC = ({ ? chartInfo.usersInProject : chartInfo.avgUsersPerProject)} > - + } /> @@ -134,6 +138,7 @@ export const InsightsCharts: VFC = ({ } @@ -144,6 +149,7 @@ export const InsightsCharts: VFC = ({ flagsPerUser={ showAllProjects ? getFlagsPerUser(flags, users) : '' } + isLoading={loading} /> = ({ } @@ -180,6 +187,7 @@ export const InsightsCharts: VFC = ({ @@ -195,6 +203,7 @@ export const InsightsCharts: VFC = ({ @@ -207,6 +216,7 @@ export const InsightsCharts: VFC = ({ metricsSummaryTrends={groupedMetricsData} allDatapointsSorted={allMetricsDatapoints} isAggregate={showAllProjects} + isLoading={loading} /> = ({ isLoading, }) => { const theme = useTheme(); - const notEnoughData = flagTrends.length < 2; + const notEnoughData = !isLoading && flagTrends.length < 2; const placeholderData = usePlaceholderData({ fill: true, type: 'double' }); const data = useMemo( diff --git a/frontend/src/component/insights/componentsChart/FlagsProjectChart/FlagsProjectChart.tsx b/frontend/src/component/insights/componentsChart/FlagsProjectChart/FlagsProjectChart.tsx index 2d596cf0c103..31f10ca03b8c 100644 --- a/frontend/src/component/insights/componentsChart/FlagsProjectChart/FlagsProjectChart.tsx +++ b/frontend/src/component/insights/componentsChart/FlagsProjectChart/FlagsProjectChart.tsx @@ -13,10 +13,12 @@ interface IFlagsProjectChartProps { projectFlagTrends: GroupedDataByProject< InstanceInsightsSchema['projectFlagTrends'] >; + isLoading?: boolean; } export const FlagsProjectChart: VFC = ({ projectFlagTrends, + isLoading, }) => { const placeholderData = usePlaceholderData({ type: 'constant', @@ -24,20 +26,22 @@ export const FlagsProjectChart: VFC = ({ const data = useProjectChartData(projectFlagTrends); const notEnoughData = useMemo( - () => (data.datasets.some((d) => d.data.length > 1) ? false : true), - [data], + () => + !isLoading && + (data.datasets.some((d) => d.data.length > 1) ? false : true), + [data, isLoading], ); return ( : false} + cover={notEnoughData ? : isLoading} /> ); }; diff --git a/frontend/src/component/insights/componentsChart/MetricsSummaryChart/MetricsSummaryChart.tsx b/frontend/src/component/insights/componentsChart/MetricsSummaryChart/MetricsSummaryChart.tsx index f48f6abd5221..53fa91689746 100644 --- a/frontend/src/component/insights/componentsChart/MetricsSummaryChart/MetricsSummaryChart.tsx +++ b/frontend/src/component/insights/componentsChart/MetricsSummaryChart/MetricsSummaryChart.tsx @@ -20,12 +20,14 @@ interface IMetricsSummaryChartProps { >; isAggregate?: boolean; allDatapointsSorted: string[]; + isLoading?: boolean; } export const MetricsSummaryChart: VFC = ({ metricsSummaryTrends, isAggregate, allDatapointsSorted, + isLoading, }) => { const theme = useTheme(); const metricsSummary = useFilledMetricsSummary( @@ -33,8 +35,10 @@ export const MetricsSummaryChart: VFC = ({ allDatapointsSorted, ); const notEnoughData = useMemo( - () => !metricsSummary.datasets.some((d) => d.data.length > 1), - [metricsSummary], + () => + !isLoading && + !metricsSummary.datasets.some((d) => d.data.length > 1), + [metricsSummary, isLoading], ); const placeholderData = usePlaceholderData(); @@ -67,7 +71,7 @@ export const MetricsSummaryChart: VFC = ({ return ( = ({ }, } } - cover={notEnoughData ? : false} + cover={notEnoughData ? : isLoading} /> ); }; diff --git a/frontend/src/component/insights/componentsChart/ProjectHealthChart/ProjectHealthChart.tsx b/frontend/src/component/insights/componentsChart/ProjectHealthChart/ProjectHealthChart.tsx index 130470abe8ea..1543b3bf8ca8 100644 --- a/frontend/src/component/insights/componentsChart/ProjectHealthChart/ProjectHealthChart.tsx +++ b/frontend/src/component/insights/componentsChart/ProjectHealthChart/ProjectHealthChart.tsx @@ -10,20 +10,24 @@ import { } from 'component/insights/components/LineChart/LineChart'; import { useTheme } from '@mui/material'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends'; +import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData'; interface IProjectHealthChartProps { projectFlagTrends: GroupedDataByProject< InstanceInsightsSchema['projectFlagTrends'] >; isAggregate?: boolean; + isLoading?: boolean; } export const ProjectHealthChart: VFC = ({ projectFlagTrends, isAggregate, + isLoading, }) => { const projectsData = useProjectChartData(projectFlagTrends); const theme = useTheme(); + const placeholderData = usePlaceholderData(); const aggregateHealthData = useMemo(() => { const labels = Array.from( @@ -85,12 +89,19 @@ export const ProjectHealthChart: VFC = ({ }; }, [projectsData, theme]); - const data = isAggregate ? aggregateHealthData : projectsData; + const aggregateOrProjectData = isAggregate + ? aggregateHealthData + : projectsData; const notEnoughData = useMemo( () => - projectsData.datasets.some((d) => d.data.length > 1) ? false : true, - [projectsData], + !isLoading && + (projectsData.datasets.some((d) => d.data.length > 1) + ? false + : true), + [projectsData, isLoading], ); + const data = + notEnoughData || isLoading ? placeholderData : aggregateOrProjectData; return ( = ({ parsing: { yAxisKey: 'health', xAxisKey: 'date' }, } } - cover={notEnoughData ? : false} + cover={notEnoughData ? : isLoading} /> ); }; diff --git a/frontend/src/component/insights/componentsChart/TimeToProductionChart/TimeToProductionChart.tsx b/frontend/src/component/insights/componentsChart/TimeToProductionChart/TimeToProductionChart.tsx index 56261aaff150..d5ce52f9fdd9 100644 --- a/frontend/src/component/insights/componentsChart/TimeToProductionChart/TimeToProductionChart.tsx +++ b/frontend/src/component/insights/componentsChart/TimeToProductionChart/TimeToProductionChart.tsx @@ -18,17 +18,21 @@ interface ITimeToProductionChartProps { InstanceInsightsSchema['projectFlagTrends'] >; isAggregate?: boolean; + isLoading?: boolean; } export const TimeToProductionChart: VFC = ({ projectFlagTrends, isAggregate, + isLoading, }) => { const theme = useTheme(); const projectsDatasets = useProjectChartData(projectFlagTrends); const notEnoughData = useMemo( - () => !projectsDatasets.datasets.some((d) => d.data.length > 1), - [projectsDatasets], + () => + !isLoading && + !projectsDatasets.datasets.some((d) => d.data.length > 1), + [projectsDatasets, isLoading], ); const aggregatedPerDay = useMemo(() => { @@ -62,7 +66,7 @@ export const TimeToProductionChart: VFC = ({ const placeholderData = usePlaceholderData(); return ( = ({ }, } } - cover={notEnoughData ? : false} + cover={notEnoughData ? : isLoading} /> ); }; diff --git a/frontend/src/component/insights/componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart.tsx b/frontend/src/component/insights/componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart.tsx index 849f30e9c393..dab2c2683a7c 100644 --- a/frontend/src/component/insights/componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart.tsx +++ b/frontend/src/component/insights/componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart.tsx @@ -92,7 +92,7 @@ export const UpdatesPerEnvironmentTypeChart: VFC< > = ({ environmentTypeTrends, isLoading }) => { const theme = useTheme(); const getEnvironmentTypeColor = useEnvironmentTypeColor(); - const notEnoughData = environmentTypeTrends?.length < 2; + const notEnoughData = !isLoading && environmentTypeTrends?.length < 2; const placeholderData = usePlaceholderData({ fill: true, type: 'double' }); const data = useMemo(() => { diff --git a/frontend/src/component/insights/componentsChart/UsersChart/UsersChart.tsx b/frontend/src/component/insights/componentsChart/UsersChart/UsersChart.tsx index af395ab15ea2..b52be62439a1 100644 --- a/frontend/src/component/insights/componentsChart/UsersChart/UsersChart.tsx +++ b/frontend/src/component/insights/componentsChart/UsersChart/UsersChart.tsx @@ -21,7 +21,7 @@ export const UsersChart: VFC = ({ }) => { const showInactiveUsers = useUiFlag('showInactiveUsers'); const theme = useTheme(); - const notEnoughData = userTrends.length < 2; + const notEnoughData = !isLoading && userTrends.length < 2; const placeholderData = usePlaceholderData({ fill: true, type: 'rising' }); const data = useMemo( () => ({ diff --git a/frontend/src/component/insights/componentsChart/UsersPerProjectChart/UsersPerProjectChart.tsx b/frontend/src/component/insights/componentsChart/UsersPerProjectChart/UsersPerProjectChart.tsx index f885e21481a2..64e97092ff34 100644 --- a/frontend/src/component/insights/componentsChart/UsersPerProjectChart/UsersPerProjectChart.tsx +++ b/frontend/src/component/insights/componentsChart/UsersPerProjectChart/UsersPerProjectChart.tsx @@ -13,10 +13,12 @@ interface IUsersPerProjectChartProps { projectFlagTrends: GroupedDataByProject< InstanceInsightsSchema['projectFlagTrends'] >; + isLoading?: boolean; } export const UsersPerProjectChart: VFC = ({ projectFlagTrends, + isLoading, }) => { const placeholderData = usePlaceholderData({ type: 'constant', @@ -24,20 +26,22 @@ export const UsersPerProjectChart: VFC = ({ const data = useProjectChartData(projectFlagTrends); const notEnoughData = useMemo( - () => (data.datasets.some((d) => d.data.length > 1) ? false : true), - [data], + () => + !isLoading && + (data.datasets.some((d) => d.data.length > 1) ? false : true), + [data, isLoading], ); return ( : false} + cover={notEnoughData ? : isLoading} /> ); }; diff --git a/frontend/src/component/insights/componentsStat/FlagStats/FlagStats.tsx b/frontend/src/component/insights/componentsStat/FlagStats/FlagStats.tsx index 9c6e77da3454..525419390727 100644 --- a/frontend/src/component/insights/componentsStat/FlagStats/FlagStats.tsx +++ b/frontend/src/component/insights/componentsStat/FlagStats/FlagStats.tsx @@ -68,17 +68,21 @@ const StyledIcon = styled(Icon)(({ theme }) => ({ interface IFlagStatsProps { count: number; flagsPerUser?: string; + isLoading?: boolean; } export const FlagStats: React.FC = ({ count, flagsPerUser, + isLoading, }) => { return ( <> - {count} + + {isLoading ? '' : count} + diff --git a/frontend/src/component/insights/componentsStat/UserStats/UserStats.tsx b/frontend/src/component/insights/componentsStat/UserStats/UserStats.tsx index 00ce67f96830..4ca725566ba8 100644 --- a/frontend/src/component/insights/componentsStat/UserStats/UserStats.tsx +++ b/frontend/src/component/insights/componentsStat/UserStats/UserStats.tsx @@ -70,9 +70,21 @@ interface IUserStatsProps { count: number; active?: number; inactive?: number; + isLoading?: boolean; } -export const UserStats: FC = ({ count, active, inactive }) => { +const StyledLoadingSkeleton = styled(Box)(() => ({ + '&:before': { + background: 'transparent', + }, +})); + +export const UserStats: FC = ({ + count, + active, + inactive, + isLoading, +}) => { const showInactiveUsers = useUiFlag('showInactiveUsers'); const showDistribution = showInactiveUsers && active !== undefined && inactive !== undefined; @@ -83,9 +95,19 @@ export const UserStats: FC = ({ count, active, inactive }) => { - {Number.parseInt(`${count}`, 10) === count - ? count - : count.toFixed(2)} + +   + + } + />