Skip to content

Commit 2a5e1a9

Browse files
committed
start to simplify
1 parent 41dfe96 commit 2a5e1a9

File tree

2 files changed

+96
-133
lines changed

2 files changed

+96
-133
lines changed

frontend/src/static/js/components/test/webstatus-stats-page.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,18 @@ describe('StatsPage', () => {
126126
);
127127

128128
// Assertions for each browser
129-
expect(element.missingOneImplementationMap.get('chrome')).to.deep.equal(
129+
expect(element.missingOneImplementationChartDataObj!).to.deep.equal(
130130
mockMissingOneCountData.get('chrome'),
131131
);
132-
expect(element.missingOneImplementationMap.get('edge')).to.deep.equal(
133-
mockMissingOneCountData.get('edge'),
134-
);
135-
expect(element.missingOneImplementationMap.get('firefox')).to.deep.equal(
136-
mockMissingOneCountData.get('firefox'),
137-
);
138-
expect(element.missingOneImplementationMap.get('safari')).to.deep.equal(
139-
mockMissingOneCountData.get('safari'),
140-
);
132+
// expect(element.missingOneImplementationChartDataObj!.get('edge')).to.deep.equal(
133+
// mockMissingOneCountData.get('edge'),
134+
// );
135+
// expect(element.missingOneImplementationChartDataObj!.get('firefox')).to.deep.equal(
136+
// mockMissingOneCountData.get('firefox'),
137+
// );
138+
// expect(element.missingOneImplementationChartDataObj!.get('safari')).to.deep.equal(
139+
// mockMissingOneCountData.get('safari'),
140+
// );
141141
});
142142
});
143143

@@ -164,7 +164,7 @@ describe('StatsPage', () => {
164164
);
165165

166166
// Directly set the missingOneImplementationMap with mock data
167-
element.missingOneImplementationMap = mockMissingOneCountData;
167+
// element.missingOneImplementationChartDataObj! = mockMissingOneCountData;
168168

169169
// Wait for the task to complete
170170
await element._loadingMissingOneTask.value;

frontend/src/static/js/components/webstatus-stats-page.ts

Lines changed: 85 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ import './webstatus-gchart';
3535
import {WebStatusDataObj} from './webstatus-gchart.js';
3636
import {BaseChartsPage} from './webstatus-base-charts-page.js';
3737

38-
/** Generate a key for globalFeatureSupport and missingOneImplementationMap. */
39-
function statsDataKey(browser: BrowsersParameter): string {
40-
return browser;
38+
interface MetricData<T> {
39+
label: string;
40+
data: Array<T>;
41+
getTimestamp: (item: T) => Date; // Function to extract timestamp
42+
getData: (item: T) => number | undefined; // Function to extract data
4143
}
4244

4345
@customElement('webstatus-stats-page')
@@ -54,26 +56,12 @@ export class StatsPage extends BaseChartsPage {
5456
@state()
5557
supportedBrowsers: BrowsersParameter[] = ALL_BROWSERS;
5658

57-
// Map from browser-channel to global feature support.
58-
// The key is generated by statsDataKey().
59-
@state()
60-
globalFeatureSupport = new Map<string, Array<BrowserReleaseFeatureMetric>>();
61-
62-
@state()
63-
globalFeatureSupportMax = Array<BaselineStatusMetric>();
64-
6559
@state()
6660
globalFeatureSupportChartOptions = {};
6761

6862
@state()
6963
globalFeatureSupportChartDataObj: WebStatusDataObj | undefined;
7064

71-
@state()
72-
missingOneImplementationMap = new Map<
73-
string,
74-
Array<BrowserReleaseFeatureMetric>
75-
>();
76-
7765
@state()
7866
missingOneImplementationChartDataObj: WebStatusDataObj | undefined;
7967

@@ -147,46 +135,53 @@ export class StatsPage extends BaseChartsPage {
147135
endDate: Date,
148136
) {
149137
if (typeof apiClient !== 'object') return;
138+
139+
const browserMetricData: Array<MetricData<BrowserReleaseFeatureMetric>> =
140+
ALL_BROWSERS.map(browser => ({
141+
label: browser,
142+
data: [],
143+
getTimestamp: (item: BrowserReleaseFeatureMetric) =>
144+
new Date(item.timestamp),
145+
getData: (item: BrowserReleaseFeatureMetric) => item.count,
146+
}));
147+
148+
const maxMetricData: MetricData<BaselineStatusMetric> = {
149+
label: 'Total number of Baseline features',
150+
data: [],
151+
getTimestamp: (item: BaselineStatusMetric) => new Date(item.timestamp),
152+
getData: (item: BaselineStatusMetric) => item.count,
153+
};
154+
155+
const allMetricData = [...browserMetricData, maxMetricData];
156+
150157
const browserPromises = ALL_BROWSERS.map(async browser => {
158+
const browserData = browserMetricData.find(
159+
data => data.label === browser,
160+
);
161+
if (!browserData) return;
162+
151163
for await (const page of apiClient.getFeatureCountsForBrowser(
152164
browser,
153165
startDate,
154166
endDate,
155167
)) {
156-
// Append the new data to existing data
157-
const existingData =
158-
this.globalFeatureSupport.get(statsDataKey(browser)) || [];
159-
this.globalFeatureSupport.set(statsDataKey(browser), [
160-
...existingData,
161-
...page,
162-
]);
168+
browserData.data.push(...page);
163169
}
164-
this.globalFeatureSupportChartDataObj = this.createDisplayDataFromMap(
165-
this.globalFeatureSupport,
166-
{
167-
label: 'Total number of Baseline features',
168-
data: this.globalFeatureSupportMax,
169-
},
170-
);
171170
});
172171

173172
const maxPromise = (async () => {
174173
for await (const page of apiClient.listAggregatedBaselineStatusCounts(
175174
startDate,
176175
endDate,
177176
)) {
178-
const existingMaxData = this.globalFeatureSupportMax || [];
179-
this.globalFeatureSupportMax = [...existingMaxData, ...page];
180-
this.globalFeatureSupportChartDataObj = this.createDisplayDataFromMap(
181-
this.globalFeatureSupport,
182-
{
183-
label: 'Total number of Baseline features',
184-
data: this.globalFeatureSupportMax,
185-
},
186-
);
177+
maxMetricData.data.push(...page);
187178
}
188179
})();
189-
await Promise.all([...browserPromises, maxPromise]); // Wait for all promises to finish
180+
181+
await Promise.all([...browserPromises, maxPromise]);
182+
183+
this.globalFeatureSupportChartDataObj =
184+
this.createDisplayDataFromMap(allMetricData);
190185
}
191186

192187
async _fetchMissingOneImplemenationCounts(
@@ -195,27 +190,36 @@ export class StatsPage extends BaseChartsPage {
195190
endDate: Date,
196191
) {
197192
if (typeof apiClient !== 'object') return;
193+
const browserMetricData: Array<MetricData<BrowserReleaseFeatureMetric>> =
194+
ALL_BROWSERS.map(browser => ({
195+
label: browser,
196+
data: [],
197+
getTimestamp: (item: BrowserReleaseFeatureMetric) =>
198+
new Date(item.timestamp),
199+
getData: (item: BrowserReleaseFeatureMetric) => item.count,
200+
}));
198201
const promises = ALL_BROWSERS.map(async browser => {
202+
const browserData = browserMetricData.find(
203+
data => data.label === browser,
204+
);
205+
if (!browserData) return;
206+
199207
const otherBrowsers = ALL_BROWSERS.filter(value => browser !== value);
200208
for await (const page of apiClient.getMissingOneImplementationCountsForBrowser(
201209
browser,
202210
otherBrowsers,
203211
startDate,
204212
endDate,
205213
)) {
206-
// Append the new data to existing data
207-
const existingData =
208-
this.missingOneImplementationMap.get(statsDataKey(browser)) || [];
209-
this.missingOneImplementationMap.set(statsDataKey(browser), [
210-
...existingData,
211-
...page,
212-
]);
214+
browserData.data.push(...page);
213215
}
214-
this.missingOneImplementationChartDataObj = this.createDisplayDataFromMap(
215-
this.missingOneImplementationMap,
216-
);
217216
});
218217
await Promise.all(promises); // Wait for all browsers to finish
218+
219+
this.missingOneImplementationChartDataObj =
220+
this.createDisplayDataFromMap<BrowserReleaseFeatureMetric>(
221+
browserMetricData,
222+
);
219223
}
220224

221225
// Make startDate and endDate reactive so that @lit/task can detect the changes.
@@ -245,7 +249,7 @@ export class StatsPage extends BaseChartsPage {
245249
startDate,
246250
endDate,
247251
);
248-
return this.globalFeatureSupport;
252+
return;
249253
},
250254
});
251255

@@ -266,102 +270,61 @@ export class StatsPage extends BaseChartsPage {
266270
startDate,
267271
endDate,
268272
);
269-
return this.missingOneImplementationMap;
273+
return;
270274
},
271275
});
272276
}
273277

274278
// Make a DataTable from the target data map.
275279
// TODO(kyleju): refactor this method acorss feature detail page
276280
// and stats page, https://github.com/GoogleChrome/webstatus.dev/issues/964.
277-
createDisplayDataFromMap(
278-
targetMap: Map<string, Array<BrowserReleaseFeatureMetric>>,
279-
maxData?: {label: string; data: Array<BaselineStatusMetric>},
281+
createDisplayDataFromMap<T>(
282+
metricDataArray: Array<MetricData<T>>,
280283
): WebStatusDataObj {
281-
// Get the list of supported browsers.
282-
const browsers = this.supportedBrowsers;
283-
284284
const dataObj: WebStatusDataObj = {cols: [], rows: []};
285285
dataObj.cols.push({type: 'date', label: 'Date', role: 'domain'});
286-
for (const browser of browsers) {
287-
dataObj.cols.push({type: 'number', label: browser, role: 'data'});
288-
}
289-
if (maxData) {
290-
dataObj.cols.push({type: 'number', label: maxData.label, role: 'data'});
291-
}
292-
293-
// Map from date to an object with counts for each browser
294-
const dateToBrowserDataMap = new Map<
295-
number,
296-
{[key: string]: number | null}
297-
>();
298286

299-
// Create a template object with all browsers initialized to null
300-
const browserNullTemplate: {[key: string]: number | null} = {};
301-
for (const browser of browsers) {
302-
browserNullTemplate[browser] = null;
287+
for (const metricData of metricDataArray) {
288+
dataObj.cols.push({
289+
type: 'number',
290+
label: metricData.label,
291+
role: 'data',
292+
});
303293
}
304294

305-
// Merge data across all browsers into one array of rows.
306-
for (const browser of browsers) {
307-
const data = targetMap.get(statsDataKey(browser));
308-
if (!data) continue;
309-
for (const row of data) {
310-
if (!row) continue;
311-
const dateSeconds = new Date(row.timestamp).getTime();
312-
const featureCount = row.count!;
313-
if (!dateToBrowserDataMap.has(dateSeconds)) {
314-
dateToBrowserDataMap.set(dateSeconds, {});
315-
}
316-
const browserCounts = dateToBrowserDataMap.get(dateSeconds)!;
317-
browserCounts[browser] = featureCount;
318-
}
319-
}
295+
const dateToDataMap = new Map<number, {[key: string]: number | null}>();
296+
297+
for (const metricData of metricDataArray) {
298+
if (!Array.isArray(metricData.data)) continue;
299+
for (const item of metricData.data) {
300+
const timestamp = metricData.getTimestamp(item);
301+
const dateSeconds = timestamp.getTime();
302+
const dataValue = metricData.getData(item);
320303

321-
// Process the maxArray (overall max data)
322-
if (maxData) {
323-
maxData.data.sort(
324-
(a, b) =>
325-
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),
326-
); // Sort maxArray if not already sorted
327-
for (const maxEntry of maxData.data) {
328-
const dateSeconds = new Date(maxEntry.timestamp).getTime();
329-
const maxCount = maxEntry.count!;
330-
331-
// If this date hasn't been encountered before, initialize it with the null template
332-
if (!dateToBrowserDataMap.has(dateSeconds)) {
333-
dateToBrowserDataMap.set(dateSeconds, {...browserNullTemplate}); // Use spread to create a copy
304+
if (!dateToDataMap.has(dateSeconds)) {
305+
dateToDataMap.set(dateSeconds, {});
334306
}
335-
const browserCounts = dateToBrowserDataMap.get(dateSeconds)!;
336-
browserCounts[maxData.label] = maxCount; // Add the max count
307+
const dateData = dateToDataMap.get(dateSeconds)!;
308+
dateData[metricData.label] = dataValue || null;
337309
}
338310
}
339311

340-
// Create array of dateToBrowserDataMap entries and sort by dateSeconds
341-
const data = Array.from(dateToBrowserDataMap.entries()).sort(
312+
const data = Array.from(dateToDataMap.entries()).sort(
342313
([d1], [d2]) => d1 - d2,
343314
);
344315

345-
// For each date, add a row to the dataTable
346-
for (const datum of data) {
347-
const dateSeconds = datum[0];
316+
for (const [dateSeconds, dateData] of data) {
348317
const date = new Date(dateSeconds);
349-
const browserCounts = datum[1];
318+
const row: [Date, ...Array<number | string | null>] = [date];
350319

351-
const row: [Date, ...Array<number | string | null>] = [date]; // Start the row with the date
352-
353-
// Make an array of browser counts, in the order of browsers.
354-
// If the browser is not in the browserCounts, add null.
355-
browsers.forEach(browser => {
356-
row.push(browserCounts[browser] || null);
357-
});
358-
359-
if (maxData) {
360-
row.push(browserCounts[maxData.label] || null); // Add max count (or null if missing)
320+
for (const metricData of metricDataArray) {
321+
row.push(
322+
dateData[metricData.label] ? dateData[metricData.label] : null,
323+
);
361324
}
362-
363325
dataObj.rows.push(row);
364326
}
327+
365328
return dataObj;
366329
}
367330

0 commit comments

Comments
 (0)