Skip to content

Commit c181b46

Browse files
author
Bastien Abadie
committed
frontend: Support suite & platform filters, fixes #101.
1 parent 08f796b commit c181b46

File tree

6 files changed

+254
-127
lines changed

6 files changed

+254
-127
lines changed

frontend/src/base.html

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<h2>
1111
<nav>
1212
{{#navbar}}
13-
<a href="#{{ path }}">{{ name }}</a>
13+
<a href="{{ route }}">{{ name }}</a>
1414
{{/navbar}}
1515
</nav>
1616
<span> : {{ total }} files</span>
@@ -47,7 +47,7 @@ <h2>
4747
<h2>
4848
<nav>
4949
{{#navbar}}
50-
<a href="#{{ revision }}:{{ path }}">{{ name }}</a>
50+
<a href="{{ route }}">{{ name }}</a>
5151
{{/navbar}}
5252
</nav>
5353
</h2>
@@ -73,7 +73,7 @@ <h2>
7373
<h2>
7474
<nav>
7575
{{#navbar}}
76-
<a href="#{{ revision }}:{{ path }}">{{ name }}</a>
76+
<a href="{{ route }}">{{ name }}</a>
7777
{{/navbar}}
7878
</nav>
7979
<span> : {{ files.length }} files</span>
@@ -88,7 +88,7 @@ <h2>
8888

8989
{{#files}}
9090
<div class="row">
91-
<span class="filename"><a href="#{{ revision }}:{{ path }}">{{ file_name }}</a></span>
91+
<span class="filename"><a href="{{ route }}">{{ file_name }}</a></span>
9292
<span>{{ children }}</span>
9393
<span>{{ coveragePercent }} %</span>
9494
</div>
@@ -102,29 +102,39 @@ <h2>
102102
<span>Revision <samp>{{ revision }}</samp> from {{ date }}</span>
103103
</script>
104104

105-
<header>
106-
<div id="menu_browser">
107-
<a href="#zero:">View the zero coverage report</a>
108-
&bull;
109-
<input type="text" id="revision" placeholder="Mercurial revision" </input>
110-
</div>
105+
<script id="menu_browser" type="x-tmpl-mustache">
106+
<a href="#view=zero&third_party=on&cpp=on&js=on=java=on&rust=on">View the zero coverage report</a>
107+
&bull;
108+
<input type="text" name="revision" placeholder="Mercurial revision" value="{{revision}}"></input>
109+
&bull;
110+
<select name="platform">
111+
<option value="all">All platforms</option>
112+
{{#platforms}}
113+
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
114+
{{/platforms}}
115+
</select>
116+
<select name="suite">
117+
<option value="all">All test suites</option>
118+
{{#suites}}
119+
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
120+
{{/suites}}
121+
</select>
122+
</script>
111123

112-
<div id="menu_zero">
113-
<input type="checkbox" name="third_party" id="third_party" checked="checked"><label for="third_party">Show third-party files</label>
114-
<input type="checkbox" name="headers" id="headers"><label for="headers">Show headers</label>
115-
<input type="checkbox" name="completely_uncovered" id="completely_uncovered"><label for="completely_uncovered">Show completely uncovered files only</label>
116-
<input type="checkbox" name="cpp" id="cpp" checked="checked"><label for="cpp">C/C++</label>
117-
<input type="checkbox" name="js" id="js" checked="checked"><label for="js">JavaScript</label>
118-
<input type="checkbox" name="java" id="java" checked="checked"><label for="java">Java</label>
119-
<input type="checkbox" name="rust" id="rust" checked="checked"><label for="rust">Rust</label>
120-
<select id="last_push">
121-
<option value="all">All</option>
122-
<option value="one_year">0 &lt; 1 year</option>
123-
<option value="two_years">1 &lt; 2 years</option>
124-
<option value="older_than_two_years">Older than 2 years</option>
125-
</select>
126-
</div>
127-
</header>
124+
<script id="menu_zero" type="x-tmpl-mustache">
125+
{{#filters}}
126+
<input type="checkbox" name="{{ key }}" id="{{ key }}" {{#checked}}checked="checked"{{/checked}}>
127+
<label for="{{ key }}">{{ message }}</label>
128+
{{/filters}}
129+
130+
<select name="last_push" id="last_push">
131+
{{#last_pushes}}
132+
<option {{#selected}}selected="selected"{{/selected}} value="{{value}}">{{message}}</option>
133+
{{/last_pushes}}
134+
</select>
135+
</script>
136+
137+
<header id="menu"></header>
128138

129139
<main id="main">
130140
<div id="message" class="message loading">Loading...</div>

frontend/src/common.js

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,34 @@
11
import Mustache from 'mustache';
2+
import { buildRoute, readRoute, updateRoute } from './route.js';
23

34
export const REV_LATEST = 'latest';
45

5-
function assert(condition, message) {
6-
if (!condition) {
7-
throw new Error(message || "Assertion failed");
8-
}
9-
}
10-
116
function domContentLoaded() {
127
return new Promise(resolve => document.addEventListener('DOMContentLoaded', resolve));
138
}
149
export const DOM_READY = domContentLoaded();
1510

16-
export async function main(load, display, opts) {
17-
// Immediately listen to DOM event
18-
11+
export async function main(load, display) {
1912
// Load initial data before DOM is available
2013
let data = await load();
2114

2215
// Wait for DOM to be ready before displaying
2316
await DOM_READY;
2417
await display(data);
18+
monitor_options();
2519

2620
// Full workflow, loading then displaying data
2721
// used for following updates
2822
let full = async function() {
2923
let data = await load();
3024
await display(data);
25+
monitor_options();
3126
};
32-
monitor_options(opts, full);
27+
28+
// React to url changes
3329
window.onhashchange = full;
3430
}
3531

36-
3732
// Coverage retrieval.
3833

3934
const COVERAGE_BACKEND_HOST = process.env.BACKEND_URL;
@@ -64,8 +59,9 @@ function cache_set(cache, key, value) {
6459
}
6560

6661
let path_coverage_cache = {};
67-
export async function get_path_coverage(path, changeset) {
68-
let data = cache_get(path_coverage_cache, `${changeset}_${path}`);
62+
export async function get_path_coverage(path, changeset, platform, suite) {
63+
let cache_key = `${changeset}_${path}_${platform}_${suite}`;
64+
let data = cache_get(path_coverage_cache, cache_key);
6965
if (data) {
7066
return data;
7167
}
@@ -74,33 +70,47 @@ export async function get_path_coverage(path, changeset) {
7470
if (changeset && changeset !== REV_LATEST) {
7571
params += `&changeset=${changeset}`;
7672
}
73+
if (platform && platform !== 'all') {
74+
params += `&platform=${platform}`;
75+
}
76+
if (suite && suite !== 'all') {
77+
params += `&suite=${suite}`;
78+
}
7779
let response = await fetch(`${COVERAGE_BACKEND_HOST}/v2/path?${params}`).catch(alert);
7880
if (response.status !== 200) {
7981
throw new Error(response.status + ' - ' + response.statusText);
8082
}
8183
data = await response.json();
8284

83-
cache_set(path_coverage_cache, `${changeset}_${path}`, data);
85+
cache_set(path_coverage_cache, cache_key, data);
8486

8587
return data;
8688
}
8789

8890
let history_cache = {};
89-
export async function get_history(path) {
91+
export async function get_history(path, platform, suite) {
9092
// Backend needs path without trailing /
9193
if (path && path.endsWith('/')) {
9294
path = path.substring(0, path.length-1);
9395
}
9496

95-
let data = cache_get(history_cache, path);
97+
let cache_key = `${path}_${platform}_${suite}`;
98+
let data = cache_get(history_cache, cache_key);
9699
if (data) {
97100
return data;
98101
}
99102

100-
let response = await fetch(`${COVERAGE_BACKEND_HOST}/v2/history?path=${path}`);
103+
let params = `path=${path}`;
104+
if (platform && platform !== 'all') {
105+
params += `&platform=${platform}`;
106+
}
107+
if (suite && suite !== 'all') {
108+
params += `&suite=${suite}`;
109+
}
110+
let response = await fetch(`${COVERAGE_BACKEND_HOST}/v2/history?${params}`);
101111
data = await response.json();
102112

103-
cache_set(history_cache, path, data);
113+
cache_set(history_cache, cache_key, data);
104114

105115
// Check data has coverage values
106116
// These values are missing when going above 2 levels right now
@@ -131,21 +141,57 @@ export async function get_zero_coverage_data() {
131141
}
132142

133143

144+
let filters_cache = {};
145+
export async function get_filters() {
146+
let data = cache_get(filters_cache, '');
147+
if (data) {
148+
return data;
149+
}
150+
151+
let response = await fetch(`${COVERAGE_BACKEND_HOST}/v2/filters`);
152+
data = await response.json();
153+
154+
cache_set(filters_cache, '', data);
155+
156+
return data;
157+
}
158+
159+
134160
// Option handling.
135161

136162
function is_enabled(opt) {
137-
let elem = document.getElementById(opt);
138-
return elem.checked;
163+
let route = readRoute();
164+
return route[opt] === 'on';
139165
}
140166

141-
function monitor_options(opts, callback) {
142-
for (let opt of opts) {
143-
let elem = document.getElementById(opt);
144-
elem.onchange = callback;
167+
function monitor_options() {
168+
// Monitor input & select changes
169+
let fields = document.querySelectorAll('input, select');
170+
for(let field of fields) {
171+
if (field.type == 'text') {
172+
// React on enter
173+
field.onkeydown = async (evt) => {
174+
if(evt.keyCode === 13) {
175+
let params = {};
176+
params[evt.target.name] = evt.target.value;
177+
updateRoute(params);
178+
}
179+
}
180+
} else {
181+
// React on change
182+
field.onchange = async (evt) => {
183+
let value = evt.target.value;
184+
if (evt.target.type == 'checkbox') {
185+
value = evt.target.checked ? 'on' : 'off';
186+
}
187+
let params = {};
188+
params[evt.target.name] = value;
189+
updateRoute(params);
190+
}
191+
}
145192
}
146193
}
147194

148-
149195
// hgmo.
150196

151197
export async function get_source(file) {
@@ -267,14 +313,14 @@ export function build_navbar(path, revision) {
267313
let links = [
268314
{
269315
'name': 'mozilla-central',
270-
'path': '',
316+
'route': buildRoute({path: '', revision})
271317
}
272318
];
273319
return links.concat(path.split('/').map(file => {
274320
base += (base ? '/' : '') + file;
275321
return {
276322
'name': file,
277-
'path': base,
323+
'route': buildRoute({path: base, revision})
278324
};
279325
}));
280326
}

0 commit comments

Comments
 (0)