Skip to content

Commit 6b1c5d0

Browse files
Add Month over Month (#1042)
* calculate month over month * add info in summary on top of page * add change arrows in summary cards above the charts * add styling unchanged monthly score + inverted * add MoM in summary viz * style MoM in the tables * fix bug categories page * add MoM to multi tech * calculate difference against same tech in multi tech view * fix lighthouse bug * make dark mode contrast higher * fix linting * fix linting
1 parent a05958f commit 6b1c5d0

File tree

11 files changed

+307
-16
lines changed

11 files changed

+307
-16
lines changed

config/techreport.json

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"metric": "good_pct",
117117
"label": "Overall good CWVs",
118118
"suffix": "%",
119+
"change": "true",
119120
"description": "Origins with overall good core web vitals.",
120121
"url": "#good-cwvs"
121122
},
@@ -125,6 +126,7 @@
125126
"metric": "median_score_pct",
126127
"label": "Lighthouse performance",
127128
"suffix": "",
129+
"change": "true",
128130
"description": "Median lighthouse performance score across tested origins.",
129131
"url": "#lighthouse"
130132
},
@@ -134,6 +136,7 @@
134136
"metric": "median_score_pct",
135137
"label": "Lighthouse accessibility",
136138
"suffix": "",
139+
"change": "true",
137140
"description": "Median lighthouse accessibility score across tested origins.",
138141
"url": "#lighthouse&median-lighthouse-over-time=accessibility"
139142
},
@@ -142,6 +145,8 @@
142145
"category": "total",
143146
"metric": "median_bytes_formatted",
144147
"label": "Page weight",
148+
"change": "true",
149+
"changeMeaning": "inverted",
145150
"description": "Median total bytes per page for across tested origins.",
146151
"url": "#page-weight"
147152
}
@@ -166,12 +171,20 @@
166171
"key": "origins",
167172
"name": "Origins"
168173
},
174+
{
175+
"key": "momString",
176+
"name": "Change",
177+
"styleChange": true,
178+
"keyNr": "momPerc"
179+
},
169180
{
170181
"key": "client",
171182
"name": "Client"
172183
}
173184
]
174185
},
186+
"summary": true,
187+
"change": true,
175188
"viz": {
176189
"title": "Origins over time",
177190
"metric": "origins",
@@ -234,6 +247,7 @@
234247
"metric": "good_pct",
235248
"label": "Good CWVs",
236249
"suffix": "%",
250+
"change": "true",
237251
"description": "Origins with overall good core web vitals.",
238252
"url": "?good-cwv-over-time=overall#good-cwvs"
239253
},
@@ -243,6 +257,7 @@
243257
"metric": "good_pct",
244258
"label": "Good LCP",
245259
"suffix": "%",
260+
"change": "true",
246261
"description": "Percentage of origins with good LCP scores (under 0.25s).",
247262
"url": "?good-cwv-over-time=LCP#good-cwvs"
248263
},
@@ -252,6 +267,7 @@
252267
"metric": "good_pct",
253268
"label": "Good CLS",
254269
"suffix": "%",
270+
"change": "true",
255271
"description": "Percentage of origins with good CLS scores (under 0.1).",
256272
"url": "?good-cwv-over-time=CLS#good-cwvs"
257273
},
@@ -261,6 +277,7 @@
261277
"metric": "good_pct",
262278
"label": "Good INP",
263279
"suffix": "%",
280+
"change": "true",
264281
"description": "Percentage of origins with good INP scores (under 200ms).",
265282
"url": "?good-cwv-over-time=INP#good-cwvs"
266283
}
@@ -330,6 +347,13 @@
330347
"name": "Eligible",
331348
"className": "eligible"
332349
},
350+
{
351+
"key": "momString",
352+
"name": "Change",
353+
"styleChange": true,
354+
"keyNr": "momPerc"
355+
356+
},
333357
{
334358
"key": "client",
335359
"name": "Client",
@@ -338,6 +362,7 @@
338362
]
339363
},
340364
"summary": true,
365+
"change": true,
341366
"viz": {
342367
"base": "pct_good_",
343368
"default": "overall",
@@ -402,6 +427,7 @@
402427
"endpoint": "lighthouse",
403428
"category": "performance",
404429
"metric": "median_score_pct",
430+
"change": "true",
405431
"label": "Performance",
406432
"url": "?median-lighthouse-over-time=performance#lighthouse",
407433
"description": "Median Lighthouse <strong>performance</strong> score."
@@ -410,6 +436,7 @@
410436
"endpoint": "lighthouse",
411437
"category": "accessibility",
412438
"metric": "median_score_pct",
439+
"change": "true",
413440
"label": "Accessibility",
414441
"url": "?median-lighthouse-over-time=accessibility#lighthouse",
415442
"description": "Median Lighthouse <strong>accessibility</strong> score."
@@ -418,6 +445,7 @@
418445
"endpoint": "lighthouse",
419446
"category": "seo",
420447
"metric": "median_score_pct",
448+
"change": "true",
421449
"label": "SEO",
422450
"url": "?median-lighthouse-over-time=seo#lighthouse",
423451
"description": "Median Lighthouse <strong>SEO</strong> score."
@@ -428,7 +456,8 @@
428456
"metric": "median_score_pct",
429457
"label": "Best Practices",
430458
"url": "?median-lighthouse-over-time=best_practices#lighthouse",
431-
"description": "Median Lighthouse <strong>best practices</strong> score."
459+
"description": "Median Lighthouse <strong>best practices</strong> score.",
460+
"change": "true"
432461
}
433462
]
434463
},
@@ -439,6 +468,7 @@
439468
"endpoint": "lighthouse",
440469
"metric": "median_score_pct",
441470
"summary": true,
471+
"change": true,
442472
"subcategory": {
443473
"base": "median_lighthouse_score_",
444474
"param": "median-lighthouse-over-time",
@@ -477,6 +507,12 @@
477507
"className": "main-cell",
478508
"viz": "progress-circle"
479509
},
510+
{
511+
"key": "momString",
512+
"name": "Change",
513+
"styleChange": true,
514+
"keyNr": "momPerc"
515+
},
480516
{
481517
"key": "client",
482518
"name": "Client",
@@ -547,21 +583,27 @@
547583
"category": "images",
548584
"metric": "median_bytes_formatted",
549585
"label": "Image Weight",
550-
"url": "?weight-over-time=image#page-weight"
586+
"url": "?weight-over-time=image#page-weight",
587+
"change": "true",
588+
"changeMeaning": "inverted"
551589
},
552590
{
553591
"endpoint": "pageWeight",
554592
"category": "js",
555593
"metric": "median_bytes_formatted",
556594
"label": "JavaScript Size",
557-
"url": "?weight-over-time=js#page-weight"
595+
"url": "?weight-over-time=js#page-weight",
596+
"change": "true",
597+
"changeMeaning": "inverted"
558598
},
559599
{
560600
"endpoint": "pageWeight",
561601
"category": "total",
562602
"metric": "median_bytes_formatted",
563603
"label": "Total Page Weight",
564-
"url": "?weight-over-time=total#page-weight"
604+
"url": "?weight-over-time=total#page-weight",
605+
"change": "true",
606+
"changeMeaning": "inverted"
565607
}
566608
]
567609
},
@@ -570,6 +612,8 @@
570612
"description": "",
571613
"id": "weight_timeseries",
572614
"summary": true,
615+
"change": true,
616+
"changeMeaning": "inverted",
573617
"endpoint": "pageWeight",
574618
"default": "images",
575619
"metric": "median_bytes",
@@ -606,6 +650,12 @@
606650
"key": "median_bytes_formatted",
607651
"className": "main-cell"
608652
},
653+
{
654+
"key": "momString",
655+
"name": "Change",
656+
"styleChange": true,
657+
"keyNr": "momPerc"
658+
},
609659
{
610660
"name": "Client",
611661
"key": "client",
@@ -777,6 +827,7 @@
777827
"endpoint": "vitals",
778828
"metric": "good_pct",
779829
"default": "overall",
830+
"change": "true",
780831
"subcategory": {
781832
"base": "pct_good_",
782833
"param": "good-cwv-over-time",
@@ -883,6 +934,7 @@
883934
"id": "lighthouse_timeseries",
884935
"endpoint": "lighthouse",
885936
"metric": "median_score_pct",
937+
"change": "true",
886938
"subcategory": {
887939
"base": "median_lighthouse_score_",
888940
"param": "median-lighthouse-over-time",
@@ -980,6 +1032,8 @@
9801032
"endpoint": "pageWeight",
9811033
"metric": "median_bytes",
9821034
"default": "total",
1035+
"change": "true",
1036+
"changeMeaning": "inverted",
9831037
"subcategory": {
9841038
"base": "median_bytes_",
9851039
"param": "median-weight-over-time",
@@ -1075,6 +1129,7 @@
10751129
"endpoint": "adoption",
10761130
"metric": "origins",
10771131
"default": "adoption",
1132+
"change": "true",
10781133
"table": {
10791134
"param":"",
10801135
"caption": "Adoption",

src/js/techreport/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,19 @@ class TechReport {
252252
return fetch(url)
253253
.then(result => result.json())
254254
.then(result => {
255+
const sortedResult = result.sort((a, b) => new Date(a.date) - new Date(b.date));
256+
let previousRow = {};
255257
// Loop through all the rows of the API result
256-
result.forEach(row => {
258+
sortedResult.forEach(row => {
257259
const parsedRow = {
258260
...row,
259261
}
260262

261263
// Parse the data and add it to the results
262264
if(api.parse) {
263265
const metric = parsedRow[api.metric] || parsedRow;
264-
parsedRow[api.metric] = api.parse(metric, parsedRow?.date);
266+
const previousMetric = previousRow[row.technology]?.[api.metric];
267+
parsedRow[api.metric] = api.parse(metric, previousMetric, parsedRow?.date);
265268
}
266269

267270
if(api.endpoint === 'technologies') {
@@ -278,6 +281,8 @@ class TechReport {
278281
allResults[row.technology].push(parsedRow);
279282
}
280283
}
284+
285+
previousRow[row.technology] = row;
281286
});
282287
})
283288
.catch(error => console.log('Something went wrong', error));

src/js/techreport/summaryCards.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
import { DataUtils } from "./utils/data";
6+
import { UIUtils } from "./utils/ui";
67

78
class SummaryCard {
89
constructor(id, pageConfig, config, filters, data) {
@@ -33,6 +34,7 @@ class SummaryCard {
3334
const key = card.dataset.key;
3435

3536
let latestValue;
37+
let latestChange;
3638

3739
if(key) {
3840
latestValue = this.data[key][metric][client] || this.data[key][metric];
@@ -45,6 +47,10 @@ class SummaryCard {
4547
const latestCategory = latestEndpoint?.find(row => row.name === category)?.[client];
4648
if(metric) {
4749
latestValue = latestCategory?.[metric];
50+
latestChange = {
51+
string: latestCategory?.momString,
52+
perc: latestCategory?.momPerc,
53+
};
4854
} else {
4955
latestValue = latestCategory;
5056
}
@@ -65,7 +71,17 @@ class SummaryCard {
6571
circle.setAttribute('style', `--offset: ${latestValue}%;`);
6672
circle.classList.add(scoreCategoryName);
6773
});
74+
}
75+
76+
if(latestChange && latestChange.string) {
77+
const changeSlot = card.querySelector('[data-slot="change"]');
78+
const changeMeaning = changeSlot?.dataset?.meaning;
6879

80+
if(changeSlot) {
81+
changeSlot.textContent = latestChange.string;
82+
const styling = UIUtils.getChangeStatus(latestChange.perc, changeMeaning);
83+
changeSlot.classList.add(styling.color, styling.direction);
84+
}
6985
}
7086
}
7187
}

src/js/techreport/table.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DataUtils } from "./utils/data";
2+
import { UIUtils } from "./utils/ui";
23

34
function formatData(tableConfig, data) {
45
const { id, config, apps } = tableConfig;
@@ -81,12 +82,18 @@ function getColumnCell(columnConfig, data, date) {
8182
const endpointData = _data?.[endpoint];
8283
const subcategoryData = endpointData?.find(row => row.name === subcategory);
8384
const value = subcategoryData?.[client]?.[column.key];
85+
let styling;
86+
87+
if(column.styleChange && column.keyNr) {
88+
styling = UIUtils.getChangeStatus(subcategoryData?.[client]?.[column.keyNr]);
89+
}
8490

8591
const cell = {
8692
...column,
8793
formattedKey: column.key,
8894
value: value,
89-
app: app
95+
app: app,
96+
styling: styling,
9097
};
9198

9299
return cell;
@@ -186,6 +193,10 @@ function updateTable(id, config, appConfig, apps, data) {
186193
wrapper.setAttribute('style', `--offset: ${value}%`);
187194
}
188195

196+
if(column.styling) {
197+
wrapper.classList.add('monthchange', column.styling.direction, column.styling.color);
198+
}
199+
189200
// Add cell to the row
190201
tr.appendChild(cell);
191202
});

src/js/techreport/tableLinked.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DataUtils } from "./utils/data";
2+
import { UIUtils } from "./utils/ui";
23

34
class TableLinked {
45
constructor(id, pageConfig, globalConfig, filters, data) {
@@ -128,6 +129,7 @@ class TableLinked {
128129
cell = document.createElement('td');
129130
const dataset = latest?.[column?.endpoint];
130131
let value = dataset?.find(entry => entry.name === column.subcategory);
132+
const changeStyle = UIUtils.getChangeStatus(value?.[component.dataset.client]?.momPerc);
131133
value = value?.[component.dataset.client]?.[column?.metric];
132134
if(column.suffix) {
133135
cellContent.innerHTML = `${value?.toLocaleString()}${column.suffix}`;
@@ -145,6 +147,11 @@ class TableLinked {
145147
}
146148

147149
cell.append(cellContent);
150+
if(column.viz === 'progress') {
151+
const monthChange = document.createElement('div');
152+
monthChange.classList.add('monthchange', changeStyle?.color, changeStyle?.direction);
153+
cell.appendChild(monthChange);
154+
}
148155
}
149156

150157
if(column.className) {

0 commit comments

Comments
 (0)