Skip to content

Commit f9e85d2

Browse files
committed
Addressed comments and updated chart label and border color
1 parent 9cdb98f commit f9e85d2

File tree

1 file changed

+133
-96
lines changed

1 file changed

+133
-96
lines changed

web-server/src/content/DoraMetrics/DoraMetricsTrend.tsx

Lines changed: 133 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import {
55
} from '@mui/icons-material';
66
import { darken, useTheme } from '@mui/material';
77
import { FC, useMemo } from 'react';
8+
9+
import { Chart2, ChartSeries } from '@/components/Chart2';
810
import { FlexBox } from '@/components/FlexBox';
911
import { Line } from '@/components/Text';
1012
import { useSelector } from '@/store';
1113
import { Deployment } from '@/types/resources';
1214
import { percentageToMultiplier } from '@/utils/datatype';
13-
import { Chart2, ChartSeries } from '@/components/Chart2';
1415

1516
const MEANINGFUL_CHANGE_THRESHOLD = 0.5;
1617

@@ -22,11 +23,14 @@ interface TrendData {
2223
}
2324

2425
const getDeploymentDurationInSeconds = (deployment: Deployment): number => {
25-
if (deployment.id?.startsWith('WORKFLOW') && typeof deployment.run_duration === 'number' && deployment.run_duration > 0) {
26+
if (
27+
deployment.id?.startsWith('WORKFLOW') &&
28+
typeof deployment.run_duration === 'number' &&
29+
deployment.run_duration > 0
30+
) {
2631
return deployment.run_duration;
2732
}
28-
29-
33+
3034
try {
3135
const conductedAt = new Date(deployment.conducted_at);
3236
const createdAt = new Date(deployment.created_at);
@@ -36,14 +40,14 @@ const getDeploymentDurationInSeconds = (deployment: Deployment): number => {
3640
const durationMs = conductedAt.getTime() - createdAt.getTime();
3741
return Math.max(0, Math.floor(durationMs / 1000));
3842
} catch (e) {
39-
console.error("Error calculating deployment duration", e);
43+
console.error('Error calculating deployment duration', e);
4044
return 0;
4145
}
4246
};
4347

44-
const getDeploymentDurationInHours = (deployment: Deployment): number => {
48+
const getDeploymentDurationInMinutes = (deployment: Deployment): number => {
4549
const seconds = getDeploymentDurationInSeconds(deployment);
46-
return +(seconds / 3600).toFixed(2);
50+
return +(seconds / 60).toFixed(2);
4751
};
4852

4953
export const calculateDeploymentTrends = (
@@ -60,13 +64,15 @@ export const calculateDeploymentTrends = (
6064
}
6165

6266
// Filter valid deployments early
63-
const validDeployments = deployments.filter(dep => {
64-
const hasValidDates = dep.conducted_at && new Date(dep.conducted_at).toString() !== 'Invalid Date';
67+
const validDeployments = deployments.filter((dep) => {
68+
const hasValidDates =
69+
dep.conducted_at &&
70+
new Date(dep.conducted_at).toString() !== 'Invalid Date';
6571

6672
if (dep.id.startsWith('WORKFLOW')) {
6773
return hasValidDates && typeof dep.run_duration === 'number';
6874
}
69-
75+
7076
return hasValidDates;
7177
});
7278

@@ -86,45 +92,53 @@ export const calculateDeploymentTrends = (
8692
const firstHalf = sortedDeployments.slice(0, midpoint);
8793
const secondHalf = sortedDeployments.slice(midpoint);
8894

89-
9095
// Calculate average duration for each half
9196
const getAvgDuration = (deps: Deployment[]) => {
92-
const totalDuration = deps.reduce((sum, dep) => sum + getDeploymentDurationInSeconds(dep), 0);
97+
const totalDuration = deps.reduce(
98+
(sum, dep) => sum + getDeploymentDurationInSeconds(dep),
99+
0
100+
);
93101
return deps.length > 0 ? totalDuration / deps.length : 0;
94102
};
95103

96104
const firstHalfAvgDuration = getAvgDuration(firstHalf);
97105
const secondHalfAvgDuration = getAvgDuration(secondHalf);
98-
99-
const durationChange = firstHalfAvgDuration
100-
? ((secondHalfAvgDuration - firstHalfAvgDuration) / firstHalfAvgDuration) * 100
106+
107+
const durationChange = firstHalfAvgDuration
108+
? ((secondHalfAvgDuration - firstHalfAvgDuration) / firstHalfAvgDuration) *
109+
100
101110
: 0;
102-
111+
103112
const avgDuration = getAvgDuration(sortedDeployments);
104113

105114
const getAvgPrCount = (deps: Deployment[]): number => {
106115
if (!deps || deps.length === 0) return 0;
107-
116+
108117
// Filter deployments that have valid PR count data
109-
const depsWithPrCount = deps.filter(dep => dep.pr_count >= 0);
110-
118+
const depsWithPrCount = deps.filter((dep) => dep.pr_count >= 0);
119+
120+
console.log('prCount', deployments[0]);
121+
111122
if (depsWithPrCount.length === 0) return 0;
112-
113-
const deploymentsByDate = depsWithPrCount.reduce((acc, dep) => {
114-
const date = new Date(dep.conducted_at).toLocaleDateString('en-US');
115-
if (!acc[date]) {
116-
acc[date] = { totalPRs: 0, count: 0 };
117-
}
118-
acc[date].totalPRs += dep.pr_count || 0;
119-
acc[date].count++;
120-
return acc;
121-
}, {} as Record<string, { totalPRs: number, count: number }>);
122-
123+
124+
const deploymentsByDate = depsWithPrCount.reduce(
125+
(acc, dep) => {
126+
const date = new Date(dep.conducted_at).toLocaleDateString('en-US');
127+
if (!acc[date]) {
128+
acc[date] = { totalPRs: 0, count: 0 };
129+
}
130+
acc[date].totalPRs += dep.pr_count || 0;
131+
acc[date].count++;
132+
return acc;
133+
},
134+
{} as Record<string, { totalPRs: number; count: number }>
135+
);
136+
123137
const dailyTotals = Object.values(deploymentsByDate);
124-
125-
const avgPrPerDay = dailyTotals.map(day => day.totalPRs / day.count);
138+
139+
const avgPrPerDay = dailyTotals.map((day) => day.totalPRs / day.count);
126140
const totalAvgPr = avgPrPerDay.reduce((sum, avg) => sum + avg, 0);
127-
141+
128142
return avgPrPerDay.length > 0 ? totalAvgPr / avgPrPerDay.length : 0;
129143
};
130144

@@ -139,7 +153,7 @@ export const calculateDeploymentTrends = (
139153

140154
return {
141155
durationTrend: {
142-
value: avgDuration,
156+
value: avgDuration / 60,
143157
change: durationChange,
144158
state: determineTrendState(durationChange, false)
145159
},
@@ -176,22 +190,24 @@ export const DeploymentTrendPill: FC<{
176190
}> = ({ label, change, state }) => {
177191
const theme = useTheme();
178192

179-
const text = (
180-
state === 'positive' ? 'Increasing ' + label : state === 'negative' ? 'Decreasing ' + label : 'Stable ' + label
181-
)
193+
const text =
194+
state === 'positive'
195+
? 'Increasing ' + label
196+
: state === 'negative'
197+
? 'Decreasing ' + label
198+
: 'Stable ' + label;
182199

183200
const useMultiplierFormat = Math.abs(change) > 100;
184201
const formattedChange = useMultiplierFormat
185202
? `${percentageToMultiplier(change)}`
186203
: `${Math.round(change)}%`;
187204

188-
const color = darken (
189-
state === 'positive'
190-
? theme.colors.success.main
191-
: theme.colors.warning.main,
192-
state === 'neutral' ? 0.5 : 0,
193-
194-
)
205+
const color = darken(
206+
state === 'positive'
207+
? theme.colors.success.main
208+
: theme.colors.warning.main,
209+
state === 'neutral' ? 0.5 : 0
210+
);
195211

196212
const icon =
197213
state === 'positive' ? (
@@ -215,10 +231,8 @@ export const DeploymentTrendPill: FC<{
215231
>
216232
<Line bold>{text}</Line>
217233
<FlexBox alignCenter>
218-
<FlexBox color={color} alignCenter>
219-
<Line bold>
220-
{formattedChange}
221-
</Line>
234+
<FlexBox color={color} alignCenter>
235+
<Line bold>{formattedChange}</Line>
222236
{icon}
223237
</FlexBox>
224238
</FlexBox>
@@ -241,60 +255,82 @@ export const DoraMetricsTrend: FC = () => {
241255
}, [allDeployments]);
242256

243257
const chartData = useMemo(() => {
244-
const validDeployments = allDeployments.filter(dep => {
245-
const hasValidDates = dep.conducted_at && new Date(dep.conducted_at).toString() !== 'Invalid Date';
246-
258+
const validDeployments = allDeployments.filter((dep) => {
259+
const hasValidDates =
260+
dep.conducted_at &&
261+
new Date(dep.conducted_at).toString() !== 'Invalid Date';
262+
247263
if (dep.id?.startsWith('WORKFLOW')) {
248-
return hasValidDates && typeof dep.run_duration === 'number' && dep.run_duration >= 0;
264+
return (
265+
hasValidDates &&
266+
typeof dep.run_duration === 'number' &&
267+
dep.run_duration >= 0
268+
);
249269
}
250-
251-
return hasValidDates && dep.created_at && new Date(dep.created_at).toString() !== 'Invalid Date';
270+
271+
return (
272+
hasValidDates &&
273+
dep.created_at &&
274+
new Date(dep.created_at).toString() !== 'Invalid Date'
275+
);
252276
});
253277

254278
if (!validDeployments.length) {
255279
return { labels: [], series: [], yAxisMax: 0 };
256280
}
257281

258282
const sortedDeployments = [...validDeployments].sort(
259-
(a, b) => new Date(a.conducted_at).getTime() - new Date(b.conducted_at).getTime()
283+
(a, b) =>
284+
new Date(a.conducted_at).getTime() - new Date(b.conducted_at).getTime()
260285
);
261286

262-
const deploymentsByDate = sortedDeployments.reduce((acc, deployment) => {
263-
const date = new Date(deployment.conducted_at).toLocaleDateString('en-US', {
264-
day: 'numeric',
265-
month: 'short'
266-
});
267-
268-
if (!acc[date]) {
269-
acc[date] = {
270-
deployments: [],
271-
totalDuration: 0,
272-
totalPRs: 0,
273-
prDeploymentCount: 0
274-
};
275-
}
276-
277-
const durationInHours = getDeploymentDurationInHours(deployment);
278-
acc[date].deployments.push(deployment);
279-
acc[date].totalDuration += durationInHours;
280-
281-
if (deployment.pr_count >= 0) {
282-
acc[date].totalPRs += deployment.pr_count || 0;
283-
acc[date].prDeploymentCount++;
284-
}
285-
286-
return acc;
287-
}, {} as Record<string, {
288-
deployments: Deployment[],
289-
totalDuration: number,
290-
totalPRs: number,
291-
prDeploymentCount: number
292-
}>);
287+
const deploymentsByDate = sortedDeployments.reduce(
288+
(acc, deployment) => {
289+
const date = new Date(deployment.conducted_at).toLocaleDateString(
290+
'en-US',
291+
{
292+
day: 'numeric',
293+
month: 'short'
294+
}
295+
);
296+
297+
if (!acc[date]) {
298+
acc[date] = {
299+
deployments: [],
300+
totalDuration: 0,
301+
totalPRs: 0,
302+
prDeploymentCount: 0
303+
};
304+
}
305+
306+
const durationInMinutes = getDeploymentDurationInMinutes(deployment);
307+
acc[date].deployments.push(deployment);
308+
acc[date].totalDuration += durationInMinutes;
309+
310+
if (deployment.pr_count >= 0) {
311+
acc[date].totalPRs += deployment.pr_count || 0;
312+
acc[date].prDeploymentCount++;
313+
}
314+
315+
return acc;
316+
},
317+
{} as Record<
318+
string,
319+
{
320+
deployments: Deployment[];
321+
totalDuration: number;
322+
totalPRs: number;
323+
prDeploymentCount: number;
324+
}
325+
>
326+
);
293327

294328
const dates = Object.keys(deploymentsByDate);
295-
const durations = dates.map(date => deploymentsByDate[date].totalDuration);
296-
297-
const prCounts = dates.map(date => {
329+
const durations = dates.map(
330+
(date) => deploymentsByDate[date].totalDuration
331+
);
332+
333+
const prCounts = dates.map((date) => {
298334
const { totalPRs, prDeploymentCount } = deploymentsByDate[date];
299335
return prDeploymentCount > 0 ? totalPRs / prDeploymentCount : 0;
300336
});
@@ -305,11 +341,11 @@ export const DoraMetricsTrend: FC = () => {
305341
const series: ChartSeries = [
306342
{
307343
type: 'bar',
308-
label: 'Deployment Duration (hours)',
344+
label: 'Deployment Duration (minutes)',
309345
data: durations,
310346
yAxisID: 'y',
311-
borderColor: theme.colors.success.main,
312-
order: 0
347+
order: 0,
348+
color: 'white'
313349
},
314350
{
315351
type: 'bar',
@@ -319,7 +355,8 @@ export const DoraMetricsTrend: FC = () => {
319355
backgroundColor: theme.colors.info.main,
320356
borderWidth: 2,
321357
tension: 0.4,
322-
order: 1
358+
order: 1,
359+
color: 'white'
323360
}
324361
];
325362

@@ -361,12 +398,12 @@ export const DoraMetricsTrend: FC = () => {
361398
position: 'left',
362399
title: {
363400
display: true,
364-
text: 'Duration (hours)',
401+
text: 'Duration (minutes)',
365402
color: theme.colors.success.main
366403
},
367404
ticks: {
368405
color: theme.colors.success.main,
369-
callback: (value) => value + 'h'
406+
callback: (value) => value + 'm'
370407
},
371408
max: chartData.yAxisMax,
372409
grid: {
@@ -402,7 +439,7 @@ export const DoraMetricsTrend: FC = () => {
402439
const label = context.dataset.label || '';
403440
const value = context.parsed.y;
404441
if (label.includes('Duration')) {
405-
return `${label}: ${value.toFixed(2)}h`;
442+
return `${label}: ${value.toFixed(2)}m`;
406443
}
407444
return `${label}: ${value.toFixed(0)}`;
408445
}

0 commit comments

Comments
 (0)