mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-31 00:16:47 +01:00
feat: ttp for all projects should show median value per day (#6656)
Separates out the calculation of the median to its own file and tested Closes # [1-2212](https://linear.app/unleash/issue/1-2212/timetoproduction-for-all-projects-should-show-the-change-in-the-median) --------- Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
parent
bce25bf0f1
commit
ce4a243165
@ -51,19 +51,19 @@ export const chartInfo = {
|
||||
'How the overall health changes over time for the selected projects.',
|
||||
},
|
||||
averageTimeToProduction: {
|
||||
title: 'Average time to production',
|
||||
title: 'Median time to production',
|
||||
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 averaged 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.',
|
||||
},
|
||||
timeToProduction: {
|
||||
title: 'Time to production',
|
||||
tooltip:
|
||||
'How the average time to production changes over time across all projects.',
|
||||
'How the median time to production changes over time across all projects.',
|
||||
},
|
||||
timeToProductionPerProject: {
|
||||
title: 'Time to production per project',
|
||||
tooltip:
|
||||
'How the average time to production changes over time for the selected projects.',
|
||||
'How the median time to production changes over time for the selected projects.',
|
||||
},
|
||||
metrics: {
|
||||
title: 'Flag evaluation metrics',
|
||||
|
@ -11,6 +11,7 @@ import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends';
|
||||
import { usePlaceholderData } from '../../hooks/usePlaceholderData';
|
||||
import { TimeToProductionTooltip } from './TimeToProductionTooltip/TimeToProductionTooltip';
|
||||
import { useTheme } from '@mui/material';
|
||||
import { medianTimeToProduction } from './median-time-to-production';
|
||||
|
||||
interface ITimeToProductionChartProps {
|
||||
projectFlagTrends: GroupedDataByProject<
|
||||
@ -19,34 +20,6 @@ interface ITimeToProductionChartProps {
|
||||
isAggregate?: boolean;
|
||||
}
|
||||
|
||||
type GroupedDataByDate<T> = Record<string, T[]>;
|
||||
|
||||
type DateResult<T> = Record<string, T>;
|
||||
|
||||
function averageTimeToProduction(
|
||||
projectsData: ExecutiveSummarySchema['projectFlagTrends'],
|
||||
): DateResult<number> {
|
||||
// Group the data by date
|
||||
const groupedData: GroupedDataByDate<number> = {};
|
||||
projectsData.forEach((item) => {
|
||||
const { date, timeToProduction } = item;
|
||||
if (!groupedData[date]) {
|
||||
groupedData[date] = [];
|
||||
}
|
||||
if (timeToProduction !== undefined) {
|
||||
groupedData[date].push(timeToProduction);
|
||||
}
|
||||
});
|
||||
// Calculate the average time to production for each date
|
||||
const averageByDate: DateResult<number> = {};
|
||||
Object.entries(groupedData).forEach(([date, times]) => {
|
||||
const sum = times.reduce((acc, curr) => acc + curr, 0);
|
||||
const average = sum / times.length;
|
||||
averageByDate[date] = average;
|
||||
});
|
||||
return averageByDate;
|
||||
}
|
||||
|
||||
export const TimeToProductionChart: VFC<ITimeToProductionChartProps> = ({
|
||||
projectFlagTrends,
|
||||
isAggregate,
|
||||
@ -59,7 +32,7 @@ export const TimeToProductionChart: VFC<ITimeToProductionChartProps> = ({
|
||||
);
|
||||
|
||||
const aggregatedPerDay = useMemo(() => {
|
||||
const result = averageTimeToProduction(
|
||||
const result = medianTimeToProduction(
|
||||
Object.values(projectsDatasets.datasets).flatMap(
|
||||
(item) => item.data,
|
||||
),
|
||||
@ -74,7 +47,7 @@ export const TimeToProductionChart: VFC<ITimeToProductionChartProps> = ({
|
||||
return {
|
||||
datasets: [
|
||||
{
|
||||
label: 'Time to production',
|
||||
label: 'Median time to production',
|
||||
data,
|
||||
borderColor: theme.palette.primary.light,
|
||||
backgroundColor: fillGradientPrimary,
|
||||
|
@ -0,0 +1,42 @@
|
||||
import { medianTimeToProduction } from './median-time-to-production';
|
||||
import type { ExecutiveSummarySchema } from 'openapi';
|
||||
|
||||
describe('medianTimeToProduction', () => {
|
||||
it('calculates the median with a single date and an odd number of projects', () => {
|
||||
const projectsData = [
|
||||
{ date: '2023-03-21', timeToProduction: 10 },
|
||||
{ date: '2023-03-21', timeToProduction: 20 },
|
||||
{ date: '2023-03-21', timeToProduction: 30 },
|
||||
] as unknown as ExecutiveSummarySchema['projectFlagTrends'];
|
||||
const expected = { '2023-03-21': 20 };
|
||||
expect(medianTimeToProduction(projectsData)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('calculates the median with a single date and an even number of projects', () => {
|
||||
const projectsData = [
|
||||
{ date: '2023-03-22', timeToProduction: 10 },
|
||||
{ date: '2023-03-22', timeToProduction: 20 },
|
||||
{ date: '2023-03-22', timeToProduction: 30 },
|
||||
{ date: '2023-03-22', timeToProduction: 40 },
|
||||
] as unknown as ExecutiveSummarySchema['projectFlagTrends'];
|
||||
const expected = { '2023-03-22': 25 };
|
||||
expect(medianTimeToProduction(projectsData)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('calculates the median for multiple dates with varying numbers of projects', () => {
|
||||
const projectsData = [
|
||||
{ date: '2023-03-23', timeToProduction: 5 },
|
||||
{ date: '2023-03-23', timeToProduction: 15 },
|
||||
{ date: '2023-03-24', timeToProduction: 10 },
|
||||
{ date: '2023-03-24', timeToProduction: 20 },
|
||||
{ date: '2023-03-24', timeToProduction: 30 },
|
||||
{ date: '2023-03-25', timeToProduction: 25 },
|
||||
] as unknown as ExecutiveSummarySchema['projectFlagTrends'];
|
||||
const expected = {
|
||||
'2023-03-23': 10,
|
||||
'2023-03-24': 20,
|
||||
'2023-03-25': 25,
|
||||
};
|
||||
expect(medianTimeToProduction(projectsData)).toEqual(expected);
|
||||
});
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
import type { ExecutiveSummarySchema } from 'openapi';
|
||||
|
||||
type GroupedDataByDate<T> = Record<string, T[]>;
|
||||
|
||||
type DateResult<T> = Record<string, T>;
|
||||
|
||||
export function medianTimeToProduction(
|
||||
projectsData: ExecutiveSummarySchema['projectFlagTrends'],
|
||||
): DateResult<number> {
|
||||
const groupedData: GroupedDataByDate<number> = {};
|
||||
projectsData.forEach((item) => {
|
||||
const { date, timeToProduction } = item;
|
||||
if (!groupedData[date]) {
|
||||
groupedData[date] = [];
|
||||
}
|
||||
if (timeToProduction !== undefined) {
|
||||
groupedData[date].push(timeToProduction);
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate the median time to production for each date
|
||||
const medianByDate: DateResult<number> = {};
|
||||
Object.entries(groupedData).forEach(([date, times]) => {
|
||||
const sortedTimes = times.sort((a, b) => a - b);
|
||||
const midIndex = Math.floor(sortedTimes.length / 2);
|
||||
|
||||
const median =
|
||||
sortedTimes.length % 2 === 0
|
||||
? (sortedTimes[midIndex - 1] + sortedTimes[midIndex]) / 2
|
||||
: sortedTimes[midIndex];
|
||||
|
||||
medianByDate[date] = median;
|
||||
});
|
||||
return medianByDate;
|
||||
}
|
Loading…
Reference in New Issue
Block a user