Skip to content

Commit e104d0e

Browse files
committed
fix: display "N+ repairs" labels correctly and limit to 8 labels max
Currently the UI may show "N+ repairs" label multiple times. With this fix, the number of repairs would be displayed correctly (showing the actual number) up to 8 distinct labels. After that, the remaining ones would be grouped into "N+ repairs".
1 parent 00f7e32 commit e104d0e

File tree

4 files changed

+124
-20
lines changed

4 files changed

+124
-20
lines changed

report-app/angular.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"builder": "@angular/build:karma",
8080
"options": {
8181
"tsConfig": "tsconfig.spec.json",
82+
"browsers": "ChromeHeadless",
8283
"assets": [
8384
{
8485
"glob": "**/*",

report-app/src/app/app.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import {TestBed} from '@angular/core/testing';
22
import {App} from './app';
3+
import {provideRouter} from '@angular/router';
34

45
describe('App', () => {
56
beforeEach(async () => {
67
await TestBed.configureTestingModule({
78
imports: [App],
9+
providers: [provideRouter([])],
810
}).compileComponents();
911
});
1012

@@ -18,6 +20,6 @@ describe('App', () => {
1820
const fixture = TestBed.createComponent(App);
1921
fixture.detectChanges();
2022
const compiled = fixture.nativeElement as HTMLElement;
21-
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, report-app');
23+
expect(compiled.querySelector('h1')?.textContent).toContain('Web Codegen Scorer');
2224
});
2325
});
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {labelByRepairCount, createRepairAttemptGraphData} from './repair-attempt-graph-builder';
2+
import {RunInfoFromReportServer} from '../../../../../runner/shared-interfaces';
3+
import {BuildResultStatus} from '../../../../../runner/workers/builder/builder-types';
4+
5+
interface MockAssessmentResult {
6+
finalAttempt: {
7+
buildResult: {
8+
status: BuildResultStatus;
9+
};
10+
};
11+
repairAttempts: number;
12+
}
13+
14+
interface MockRunInfo {
15+
results: MockAssessmentResult[];
16+
}
17+
18+
describe('repair-attempt-graph-builder', () => {
19+
describe('labelByRepairCount', () => {
20+
it('should return "1 repair" for 1', () => {
21+
expect(labelByRepairCount(1)).toBe('1 repair');
22+
});
23+
24+
it('should return "2 repairs" for 2', () => {
25+
expect(labelByRepairCount(2)).toBe('2 repairs');
26+
});
27+
28+
it('should return "8 repairs" for 8', () => {
29+
expect(labelByRepairCount(8)).toBe('8 repairs');
30+
});
31+
32+
it('should return "9 repairs" for 9', () => {
33+
expect(labelByRepairCount(9)).toBe('9 repairs');
34+
});
35+
});
36+
37+
describe('createRepairAttemptGraphData', () => {
38+
it('should group repair attempt labels beyond 8', () => {
39+
const mockReport: MockRunInfo = {
40+
results: [
41+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 1},
42+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 2},
43+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 3},
44+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 4},
45+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 5},
46+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 6},
47+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 7},
48+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 8},
49+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 9},
50+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 10},
51+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 11},
52+
],
53+
};
54+
55+
const data = createRepairAttemptGraphData(mockReport as unknown as RunInfoFromReportServer);
56+
57+
expect(data.length).toBe(9);
58+
expect(data[0].label).toBe('1 repair');
59+
expect(data[1].label).toBe('2 repairs');
60+
expect(data[7].label).toBe('8 repairs');
61+
expect(data[8].label).toBe('9+ repairs');
62+
});
63+
64+
it('should not group if distinct counts <= 8', () => {
65+
const mockReport: MockRunInfo = {
66+
results: [
67+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 1},
68+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 3},
69+
{finalAttempt: {buildResult: {status: BuildResultStatus.SUCCESS}}, repairAttempts: 5},
70+
],
71+
};
72+
73+
const data = createRepairAttemptGraphData(mockReport as unknown as RunInfoFromReportServer);
74+
75+
expect(data.length).toBe(3);
76+
expect(data[0].label).toBe('1 repair');
77+
expect(data[1].label).toBe('3 repairs');
78+
expect(data[2].label).toBe('5 repairs');
79+
});
80+
});
81+
});

report-app/src/app/pages/report-viewer/repair-attempt-graph-builder.ts

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {BuildResultStatus} from '../../../../../runner/workers/builder/builder-t
33
import {ScoreCssVariable} from '../../shared/scoring';
44
import {StackedBarChartData} from '../../shared/visualization/stacked-bar-chart/stacked-bar-chart';
55

6+
const MAX_VISIBLE_REPAIR_COUNT = 8;
7+
68
/**
79
* Calculates the average number of repair attempts performed in a run.
810
*/
@@ -52,17 +54,41 @@ export function createRepairAttemptGraphData(report: RunInfoFromReportServer) {
5254
.filter((k): k is number => typeof k === 'number')
5355
.sort((a, b) => a - b);
5456

55-
// This graph might involve a bunch of sections. We want to scale them among all the possible color "grades".
57+
if (intermediateRepairKeys.length <= MAX_VISIBLE_REPAIR_COUNT) {
58+
for (const repairCount of intermediateRepairKeys) {
59+
const applicationCount = repairsToAppCount.get(repairCount);
60+
if (!applicationCount) continue;
5661

57-
for (let repairCount = 1; repairCount <= maxRepairCount; repairCount++) {
58-
const applicationCount = repairsToAppCount.get(repairCount);
59-
if (!applicationCount) continue;
62+
data.push({
63+
label: labelByRepairCount(repairCount),
64+
color: colorByRepairCount(repairCount),
65+
value: applicationCount,
66+
});
67+
}
68+
} else {
69+
const visibleKeys = intermediateRepairKeys.slice(0, MAX_VISIBLE_REPAIR_COUNT);
70+
const hiddenKeys = intermediateRepairKeys.slice(MAX_VISIBLE_REPAIR_COUNT);
71+
const maxVisible = visibleKeys[visibleKeys.length - 1];
6072

61-
data.push({
62-
label: labelByRepairCount(repairCount),
63-
color: colorByRepairCount(repairCount),
64-
value: applicationCount,
65-
});
73+
for (const repairCount of visibleKeys) {
74+
const applicationCount = repairsToAppCount.get(repairCount);
75+
if (!applicationCount) continue;
76+
77+
data.push({
78+
label: labelByRepairCount(repairCount),
79+
color: colorByRepairCount(repairCount),
80+
value: applicationCount,
81+
});
82+
}
83+
84+
const groupValue = hiddenKeys.reduce((acc, k) => acc + (repairsToAppCount.get(k) ?? 0), 0);
85+
if (groupValue > 0) {
86+
data.push({
87+
label: `${maxVisible + 1}+ repairs`,
88+
color: colorByRepairCount(maxVisible + 1),
89+
value: groupValue,
90+
});
91+
}
6692
}
6793

6894
// Handle 'Build failed even after all retries' - always maps to the "failure" grade.
@@ -77,17 +103,11 @@ export function createRepairAttemptGraphData(report: RunInfoFromReportServer) {
77103
return data;
78104
}
79105

80-
function labelByRepairCount(repairCount: number): string {
81-
switch (repairCount) {
82-
case 1:
83-
return '1 repair';
84-
case 2:
85-
case 3:
86-
case 4:
87-
return `${repairCount} repairs`;
88-
default:
89-
return '5+ repairs';
106+
export function labelByRepairCount(repairCount: number): string {
107+
if (repairCount === 1) {
108+
return '1 repair';
90109
}
110+
return `${repairCount} repairs`;
91111
}
92112

93113
function colorByRepairCount(repairCount: number): string {

0 commit comments

Comments
 (0)