Skip to content

Commit 5647635

Browse files
La0marco-c
authored andcommitted
frontend: Support suite and platform filters (#143)
Also, store input states in url, fixes #101
1 parent 3483a72 commit 5647635

File tree

6 files changed

+285
-129
lines changed

6 files changed

+285
-129
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">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: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,35 @@
11
import Mustache from 'mustache';
2+
import { buildRoute, readRoute, updateRoute } from './route.js';
3+
import {ZERO_COVERAGE_FILTERS} from './zero_coverage_report.js';
24

35
export const REV_LATEST = 'latest';
46

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

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

2216
// Wait for DOM to be ready before displaying
2317
await DOM_READY;
2418
await display(data);
19+
monitor_options();
2520

2621
// Full workflow, loading then displaying data
2722
// used for following updates
2823
let full = async function() {
2924
let data = await load();
3025
await display(data);
26+
monitor_options();
3127
};
32-
monitor_options(opts, full);
28+
29+
// React to url changes
3330
window.onhashchange = full;
3431
}
3532

36-
3733
// Coverage retrieval.
3834

3935
const COVERAGE_BACKEND_HOST = process.env.BACKEND_URL;
@@ -64,8 +60,9 @@ function cache_set(cache, key, value) {
6460
}
6561

6662
let path_coverage_cache = {};
67-
export async function get_path_coverage(path, changeset) {
68-
let data = cache_get(path_coverage_cache, `${changeset}_${path}`);
63+
export async function get_path_coverage(path, changeset, platform, suite) {
64+
let cache_key = `${changeset}_${path}_${platform}_${suite}`;
65+
let data = cache_get(path_coverage_cache, cache_key);
6966
if (data) {
7067
return data;
7168
}
@@ -74,33 +71,47 @@ export async function get_path_coverage(path, changeset) {
7471
if (changeset && changeset !== REV_LATEST) {
7572
params += `&changeset=${changeset}`;
7673
}
74+
if (platform && platform !== 'all') {
75+
params += `&platform=${platform}`;
76+
}
77+
if (suite && suite !== 'all') {
78+
params += `&suite=${suite}`;
79+
}
7780
let response = await fetch(`${COVERAGE_BACKEND_HOST}/v2/path?${params}`).catch(alert);
7881
if (response.status !== 200) {
7982
throw new Error(response.status + ' - ' + response.statusText);
8083
}
8184
data = await response.json();
8285

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

8588
return data;
8689
}
8790

8891
let history_cache = {};
89-
export async function get_history(path) {
92+
export async function get_history(path, platform, suite) {
9093
// Backend needs path without trailing /
9194
if (path && path.endsWith('/')) {
9295
path = path.substring(0, path.length-1);
9396
}
9497

95-
let data = cache_get(history_cache, path);
98+
let cache_key = `${path}_${platform}_${suite}`;
99+
let data = cache_get(history_cache, cache_key);
96100
if (data) {
97101
return data;
98102
}
99103

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

103-
cache_set(history_cache, path, data);
114+
cache_set(history_cache, cache_key, data);
104115

105116
// Check data has coverage values
106117
// These values are missing when going above 2 levels right now
@@ -131,20 +142,62 @@ export async function get_zero_coverage_data() {
131142
}
132143

133144

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

136-
function is_enabled(opt) {
137-
let elem = document.getElementById(opt);
138-
return elem.checked;
157+
return data;
139158
}
140159

141-
function monitor_options(opts, callback) {
142-
for (let opt of opts) {
143-
let elem = document.getElementById(opt);
144-
elem.onchange = callback;
160+
161+
// Option handling.
162+
163+
export function is_enabled(opt) {
164+
let route = readRoute();
165+
let value = 'off';
166+
if (route[opt]) {
167+
value = route[opt];
168+
} else if (ZERO_COVERAGE_FILTERS[opt]) {
169+
value = ZERO_COVERAGE_FILTERS[opt].default_value;
145170
}
171+
return value === 'on';
146172
}
147173

174+
function monitor_options() {
175+
// Monitor input & select changes
176+
let fields = document.querySelectorAll('input, select');
177+
for(let field of fields) {
178+
if (field.type == 'text') {
179+
// React on enter
180+
field.onkeydown = async (evt) => {
181+
if(evt.keyCode === 13) {
182+
let params = {};
183+
params[evt.target.name] = evt.target.value;
184+
updateRoute(params);
185+
}
186+
}
187+
} else {
188+
// React on change
189+
field.onchange = async (evt) => {
190+
let value = evt.target.value;
191+
if (evt.target.type == 'checkbox') {
192+
value = evt.target.checked ? 'on' : 'off';
193+
}
194+
let params = {};
195+
params[evt.target.name] = value;
196+
updateRoute(params);
197+
}
198+
}
199+
}
200+
}
148201

149202
// hgmo.
150203

@@ -267,14 +320,14 @@ export function build_navbar(path, revision) {
267320
let links = [
268321
{
269322
'name': 'mozilla-central',
270-
'path': '',
323+
'route': buildRoute({path: '', revision})
271324
}
272325
];
273326
return links.concat(path.split('/').map(file => {
274327
base += (base ? '/' : '') + file;
275328
return {
276329
'name': file,
277-
'path': base,
330+
'route': buildRoute({path: base, revision})
278331
};
279332
}));
280333
}

0 commit comments

Comments
 (0)