1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00

fix: chart info naming bug fix (#6660)

Rename param

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
andreas-unleash 2024-03-21 15:16:01 +02:00 committed by GitHub
parent 2f7580e6b1
commit 9233d4ca33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 119 additions and 106 deletions

View File

@ -41,7 +41,7 @@ interface IChartsProps {
averageHealth?: string; averageHealth?: string;
flagsPerUser?: string; flagsPerUser?: string;
}; };
avgDaysToProduction: number; medianTimeToProduction: number;
loading: boolean; loading: boolean;
projects: string[]; projects: string[];
} }
@ -71,7 +71,7 @@ export const Charts: VFC<IChartsProps> = ({
userTrends, userTrends,
groupedProjectsData, groupedProjectsData,
flagTrends, flagTrends,
avgDaysToProduction, medianTimeToProduction,
groupedMetricsData, groupedMetricsData,
environmentTypeTrends, environmentTypeTrends,
loading, loading,
@ -165,8 +165,10 @@ export const Charts: VFC<IChartsProps> = ({
isAggregate={showAllProjects} isAggregate={showAllProjects}
/> />
</ChartWidget> </ChartWidget>
<Widget {...chartInfo.averageTimeToProduction}> <Widget {...chartInfo.medianTimeToProduction}>
<TimeToProduction daysToProduction={avgDaysToProduction} /> <TimeToProduction
daysToProduction={medianTimeToProduction}
/>
</Widget> </Widget>
<ChartWidget <ChartWidget
{...(showAllProjects {...(showAllProjects

View File

@ -50,7 +50,7 @@ export const chartInfo = {
tooltip: tooltip:
'How the overall health changes over time for the selected projects.', 'How the overall health changes over time for the selected projects.',
}, },
averageTimeToProduction: { medianTimeToProduction: {
title: 'Median time to production', title: 'Median time to production',
tooltip: tooltip:
'How long does it currently take on average from when a feature flag was created until it was enabled in a "production" type environment. This is calculated only from feature flags of the type "release" and is the median across the selected projects.', 'How long does it currently take on average from when a feature flag was created until it was enabled in a "production" type environment. This is calculated only from feature flags of the type "release" and is the median across the selected projects.',
@ -63,7 +63,7 @@ export const chartInfo = {
timeToProductionPerProject: { timeToProductionPerProject: {
title: 'Time to production per project', title: 'Time to production per project',
tooltip: tooltip:
'How the median time to production changes over time for the selected projects.', 'How the average time to production changes over time for the selected projects.',
}, },
metrics: { metrics: {
title: 'Flag evaluation metrics', title: 'Flag evaluation metrics',

View File

@ -1,48 +0,0 @@
import { useAvgTimeToProduction } from './useAvgTimeToProduction';
import { renderHook } from '@testing-library/react-hooks';
describe('useAvgTimeToProduction', () => {
test('returns 0 when projectsData is empty', () => {
const projectsData = {};
const { result } = renderHook(() =>
useAvgTimeToProduction(projectsData),
);
expect(result.current).toBe(0);
});
test('calculates average time to production based on the latest date correctly', () => {
const projectsData = {
project1: [
{ timeToProduction: 10, date: '2023-01-01' },
{ timeToProduction: 20, date: '2023-02-01' },
],
project2: [
{ timeToProduction: 15, date: '2023-01-15' },
{ timeToProduction: 25, date: '2023-02-15' },
],
} as any;
const { result } = renderHook(() =>
useAvgTimeToProduction(projectsData),
);
// Expect average of the latest timeToProductions (20 from project1 and 25 from project2)
expect(result.current).toBe(22.5);
});
test('ignores projects without time to production data in their latest entries', () => {
const projectsData = {
project1: [
{ timeToProduction: 10, date: '2023-01-01' },
{ timeToProduction: 20, date: '2023-02-01' },
],
project2: [
{ date: '2023-01-15' },
{ timeToProduction: 25, date: '2023-01-10' },
],
} as any;
const { result } = renderHook(() =>
useAvgTimeToProduction(projectsData),
);
// Since project2's latest entry doesn't have timeToProduction, only project1's latest is considered
expect(result.current).toBe(20);
});
});

View File

@ -1,48 +0,0 @@
import { useMemo } from 'react';
import type {
ExecutiveSummarySchema,
ExecutiveSummarySchemaProjectFlagTrendsItem,
} from 'openapi';
import type { GroupedDataByProject } from './useGroupedProjectTrends';
const validTrend = (trend: ExecutiveSummarySchemaProjectFlagTrendsItem) =>
Boolean(trend) && Boolean(trend.timeToProduction);
export const useAvgTimeToProduction = (
projectsData: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends']
>,
) =>
useMemo(() => {
let totalProjects = Object.keys(projectsData).length;
if (totalProjects === 0) {
return 0;
}
const totalAvgTimeToProduction = Object.entries(projectsData).reduce(
(acc, [_, trends]) => {
const latestTrend = trends.reduce(
(latest, current) =>
new Date(latest.date) < new Date(current.date)
? current
: latest,
trends[0],
);
// If there's no valid latest trend, this project won't contribute to the average
if (!validTrend(latestTrend)) {
totalProjects--;
return acc;
}
const timeToProduction = latestTrend.timeToProduction || 0;
return acc + timeToProduction;
},
0,
);
const overallAverage = totalAvgTimeToProduction / totalProjects;
return overallAverage;
}, [projectsData]);

View File

@ -3,7 +3,7 @@ import type { ExecutiveSummarySchema } from 'openapi';
import { useFilteredTrends } from './useFilteredTrends'; import { useFilteredTrends } from './useFilteredTrends';
import { useGroupedProjectTrends } from './useGroupedProjectTrends'; import { useGroupedProjectTrends } from './useGroupedProjectTrends';
import { useFilteredFlagsSummary } from './useFilteredFlagsSummary'; import { useFilteredFlagsSummary } from './useFilteredFlagsSummary';
import { useAvgTimeToProduction } from './useAvgTimeToProduction'; import { useMedianTimeToProduction } from './useMedianTimeToProduction';
export const useDashboardData = ( export const useDashboardData = (
executiveDashboardData: ExecutiveSummarySchema, executiveDashboardData: ExecutiveSummarySchema,
@ -27,7 +27,8 @@ export const useDashboardData = (
executiveDashboardData.users, executiveDashboardData.users,
); );
const avgDaysToProduction = useAvgTimeToProduction(groupedProjectsData); const medianTimeToProduction =
useMedianTimeToProduction(groupedProjectsData);
return useMemo( return useMemo(
() => ({ () => ({
@ -39,7 +40,7 @@ export const useDashboardData = (
users: executiveDashboardData.users, users: executiveDashboardData.users,
environmentTypeTrends: executiveDashboardData.environmentTypeTrends, environmentTypeTrends: executiveDashboardData.environmentTypeTrends,
summary, summary,
avgDaysToProduction, medianTimeToProduction,
}), }),
[ [
executiveDashboardData, executiveDashboardData,
@ -49,7 +50,7 @@ export const useDashboardData = (
metricsData, metricsData,
groupedMetricsData, groupedMetricsData,
summary, summary,
avgDaysToProduction, medianTimeToProduction,
], ],
); );
}; };

View File

@ -0,0 +1,63 @@
import { useMedianTimeToProduction } from './useMedianTimeToProduction';
import { renderHook } from '@testing-library/react-hooks';
describe('useMedianTimeToProduction', () => {
test('returns 0 when projectsData is empty', () => {
const projectsData = {};
const { result } = renderHook(() =>
useMedianTimeToProduction(projectsData),
);
expect(result.current).toBe(0);
});
test('calculates median time to production correctly with even number of projects', () => {
const projectsData = {
project1: [
{ timeToProduction: 10, date: '2023-01-01' },
{ timeToProduction: 20, date: '2023-02-01' },
],
project2: [
{ timeToProduction: 15, date: '2023-01-15' },
{ timeToProduction: 25, date: '2023-02-15' },
],
project3: [{ timeToProduction: 30, date: '2023-01-20' }],
} as any;
const { result } = renderHook(() =>
useMedianTimeToProduction(projectsData),
);
// With sorted timeToProductions [10, 15, 20, 25, 30], median is the middle value, 20.
expect(result.current).toBe(20);
});
test('calculates median time to production correctly with odd number of projects', () => {
const projectsData = {
project1: [
{ timeToProduction: 10, date: '2023-01-01' },
{ timeToProduction: 20, date: '2023-02-01' },
],
project2: [{ timeToProduction: 15, date: '2023-01-15' }],
} as any;
const { result } = renderHook(() =>
useMedianTimeToProduction(projectsData),
);
// With sorted timeToProductions [10, 15, 20], median is the middle value, 15.
expect(result.current).toBe(15);
});
test('correctly handles all valid time to production values', () => {
const projectsData = {
project1: [{ timeToProduction: 10, date: '2023-01-01' }],
project2: [{ timeToProduction: 25, date: '2023-01-10' }],
project3: [{ date: '2023-01-15' }],
project4: [
{ timeToProduction: 30, date: '2023-02-01' },
{ timeToProduction: 20, date: '2023-02-02' },
],
} as any;
const { result } = renderHook(() =>
useMedianTimeToProduction(projectsData),
);
// With sorted timeToProductions [10, 20, 25, 30], the median is the average of 20 and 25, i.e., 22.5.
expect(result.current).toBe(22.5);
});
});

View File

@ -0,0 +1,43 @@
import { useMemo } from 'react';
import type {
ExecutiveSummarySchema,
ExecutiveSummarySchemaProjectFlagTrendsItem,
} from 'openapi';
import type { GroupedDataByProject } from './useGroupedProjectTrends';
const validTrend = (trend: ExecutiveSummarySchemaProjectFlagTrendsItem) =>
Boolean(trend) && Boolean(trend.timeToProduction);
export const useMedianTimeToProduction = (
projectsData: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends']
>,
) =>
useMemo(() => {
const timesToProduction: number[] = [];
Object.values(projectsData).forEach((trends) => {
trends.forEach((trend) => {
if (validTrend(trend)) {
timesToProduction.push(trend.timeToProduction!);
}
});
});
if (timesToProduction.length === 0) {
return 0;
}
timesToProduction.sort((a, b) => a - b);
const midIndex = Math.floor(timesToProduction.length / 2);
const median =
timesToProduction.length % 2 === 0
? (timesToProduction[midIndex - 1] +
timesToProduction[midIndex]) /
2
: timesToProduction[midIndex];
return median;
}, [projectsData]);