summaryrefslogtreecommitdiffstats
path: root/non-puppet/qtmetrics2
diff options
context:
space:
mode:
authorJuha Sippola <juhasippola@outlook.com>2015-09-08 16:54:04 +0300
committerTony Sarajärvi <tony.sarajarvi@theqtcompany.com>2015-09-16 07:34:42 +0000
commitc11438479b5ae3da4ba7d46e5d88c3c000028b59 (patch)
tree04b0368ceb2670878adc021ff3fca654c5b0678b /non-puppet/qtmetrics2
parenta99be616162ea0706ebf4c01ae9e983a2cb04fb3 (diff)
Qt Metrics 2 (v0.19): Ajax for selected pages
Added Ajax functionality to testset project, top failures and flaky testsets pages as they (or their database queries) currently take the longest time to download. Change-Id: I54bc26b9237a34ac7908896e7ca024989b02c6e5 Reviewed-by: Tony Sarajärvi <tony.sarajarvi@theqtcompany.com>
Diffstat (limited to 'non-puppet/qtmetrics2')
-rw-r--r--non-puppet/qtmetrics2/index.php60
-rw-r--r--non-puppet/qtmetrics2/scripts/ajax.js103
-rw-r--r--non-puppet/qtmetrics2/styles/qtmetrics.css5
-rw-r--r--non-puppet/qtmetrics2/templates/about.html4
-rw-r--r--non-puppet/qtmetrics2/templates/testset_project.html246
-rw-r--r--non-puppet/qtmetrics2/templates/testset_project_data_latest.html136
-rw-r--r--non-puppet/qtmetrics2/templates/testset_project_data_results.html188
-rw-r--r--non-puppet/qtmetrics2/templates/testsets_flaky.html69
-rw-r--r--non-puppet/qtmetrics2/templates/testsets_flaky_data.html108
-rw-r--r--non-puppet/qtmetrics2/templates/testsets_top.html86
-rw-r--r--non-puppet/qtmetrics2/templates/testsets_top_data.html125
11 files changed, 746 insertions, 384 deletions
diff --git a/non-puppet/qtmetrics2/index.php b/non-puppet/qtmetrics2/index.php
index 909e1c0..104a819 100644
--- a/non-puppet/qtmetrics2/index.php
+++ b/non-puppet/qtmetrics2/index.php
@@ -34,7 +34,7 @@
/**
* Qt Metrics API
- * @since 03-08-2015
+ * @since 05-08-2015
* @author Juha Sippola
*/
@@ -201,19 +201,37 @@ $app->get('/testsetproject/:project', function($project) use($app)
array('name' => 'home', 'link' => Slim\Slim::getInstance()->urlFor('root')),
array('name' => 'overview', 'link' => Slim\Slim::getInstance()->urlFor('overview'))
);
- $confRoute = str_replace('/:conf', '', Slim\Slim::getInstance()->urlFor('conf'));
$app->render('testset_project.html', array(
'root' => Slim\Slim::getInstance()->urlFor('root'),
'breadcrumb' => $breadcrumb,
- 'confRoute' => $confRoute,
'refreshed' => Factory::db()->getDbRefreshed() . ' (GMT)',
'masterProject' => $ini['master_build_project'],
'masterState' => $ini['master_build_state'],
+ 'project' => $project
+ ));
+})->name('testsetproject');
+
+$app->get('/data/testsetproject/latest/:project', function($project) use($app)
+{
+$project = strip_tags($project);
+ $ini = Factory::conf();
+ $app->render('testset_project_data_latest.html', array(
'project' => $project,
'latestTestsetRuns' => Factory::db()->getLatestTestsetProjectBranchTestsetResults(
$project,
$ini['master_build_project'],
- $ini['master_build_state']),
+ $ini['master_build_state'])
+ ));
+});
+
+$app->get('/data/testsetproject/results/:project', function($project) use($app)
+{
+$project = strip_tags($project);
+ $ini = Factory::conf();
+ $confRoute = str_replace('/:conf', '', Slim\Slim::getInstance()->urlFor('conf'));
+ $app->render('testset_project_data_results.html', array(
+ 'confRoute' => $confRoute,
+ 'project' => $project,
'projectRuns' => Factory::createProjectRuns(
$ini['master_build_project'],
$ini['master_build_state']), // managed as objects
@@ -222,7 +240,7 @@ $app->get('/testsetproject/:project', function($project) use($app)
$ini['master_build_project'],
$ini['master_build_state'])
));
-})->name('testsetproject');
+});
/**
* UI route: /conf/:conf (GET)
@@ -334,19 +352,30 @@ $app->get('/test/top', function() use($app)
$app->render('testsets_top.html', array(
'root' => Slim\Slim::getInstance()->urlFor('root'),
'breadcrumb' => $breadcrumb,
- 'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
'refreshed' => Factory::db()->getDbRefreshed() . ' (GMT)',
'topN' => $ini['top_failures_n'],
'lastDays' => $ini['top_failures_last_days'],
'sinceDate' => $since,
'masterProject' => $ini['master_build_project'],
- 'masterState' => $ini['master_build_state'],
+ 'masterState' => $ini['master_build_state']
+ ));
+})->name('top');
+
+$app->get('/data/test/top', function() use($app)
+{
+ $ini = Factory::conf();
+ $days = intval($ini['top_failures_last_days']) - 1;
+ $since = Factory::getSinceDate($days);
+ $app->render('testsets_top_data.html', array(
+ 'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
+ 'lastDays' => $ini['top_failures_last_days'],
+ 'sinceDate' => $since,
'testsets' => Factory::createTestsets(
Factory::LIST_FAILURES,
$ini['master_build_project'],
$ini['master_build_state']) // managed as objects
));
-})->name('top');
+});
/**
* UI route: /test/flaky (GET)
@@ -363,17 +392,28 @@ $app->get('/test/flaky', function() use($app)
$app->render('testsets_flaky.html', array(
'root' => Slim\Slim::getInstance()->urlFor('root'),
'breadcrumb' => $breadcrumb,
- 'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
'refreshed' => Factory::db()->getDbRefreshed() . ' (GMT)',
'topN' => $ini['flaky_testsets_n'],
'lastDays' => $ini['flaky_testsets_last_days'],
+ 'sinceDate' => $since
+ ));
+})->name('flaky');
+
+$app->get('/data/test/flaky', function() use($app)
+{
+ $ini = Factory::conf();
+ $days = intval($ini['flaky_testsets_last_days']) - 1;
+ $since = Factory::getSinceDate($days);
+ $app->render('testsets_flaky_data.html', array(
+ 'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
+ 'lastDays' => $ini['flaky_testsets_last_days'],
'sinceDate' => $since,
'testsets' => Factory::createTestsets(
Factory::LIST_FLAKY,
null,
null) // managed as objects
));
-})->name('flaky');
+});
/**
* UI route: /testset/:testset/:project (GET)
diff --git a/non-puppet/qtmetrics2/scripts/ajax.js b/non-puppet/qtmetrics2/scripts/ajax.js
new file mode 100644
index 0000000..b8be6fa
--- /dev/null
+++ b/non-puppet/qtmetrics2/scripts/ajax.js
@@ -0,0 +1,103 @@
+/*
+#############################################################################
+##
+## Copyright (C) 2015 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Quality Assurance module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL21$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see http://www.qt.io/terms-conditions. For further
+## information use the contact form at http://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 or version 3 as published by the Free
+## Software Foundation and appearing in the file LICENSE.LGPLv21 and
+## LICENSE.LGPLv3 included in the packaging of this file. Please review the
+## following information to ensure the GNU Lesser General Public License
+## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## As a special exception, The Qt Company gives you certain additional
+## rights. These rights are described in The Qt Company LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+/**
+ * Ajax route calls
+ * @since 05-08-2015
+ * @author Juha Sippola
+ */
+
+$(function () {
+
+ // Get all div ids on a page to call correct routes
+ var div;
+ var divs = [];
+ $(".container-fluid").find("div").each(function(){ divs.push(this.id); });
+
+ // Testset project / latest status
+ var project;
+ if ($.inArray('testset_project_data_latest', divs) > -1) {
+ project = $('#project').html();
+ $.ajax({
+ url: "data/testsetproject/latest/" + project,
+ dataType: "html",
+ cache: true
+ })
+ .done(function( html ) {
+ console.log(this.url + " done");
+ $('#testset_project_data_latest').html(html);
+ });
+ }
+
+ // Testset project / results in branches
+ if ($.inArray('testset_project_data_results', divs) > -1) {
+ project = $('#project').html();
+ $.ajax({
+ url: "data/testsetproject/results/" + project,
+ dataType: "html",
+ cache: true
+ })
+ .done(function( html ) {
+ console.log(this.url + " done");
+ $('#testset_project_data_results').html(html);
+ });
+ }
+
+ // Top failures
+ if ($.inArray('testsets_top_data', divs) > -1) {
+ $.ajax({
+ url: "data/test/top",
+ dataType: "html",
+ cache: true
+ })
+ .done(function( html ) {
+ console.log(this.url + " done");
+ $('#testsets_top_data').html(html);
+ });
+ }
+
+ // Flaky testsets
+ if ($.inArray('flaky_testsets_data', divs) > -1) {
+ $.ajax({
+ url: "data/test/flaky",
+ dataType: "html",
+ cache: true
+ })
+ .done(function( html ) {
+ console.log(this.url + " done");
+ $('#flaky_testsets_data').html(html);
+ });
+ }
+
+});
diff --git a/non-puppet/qtmetrics2/styles/qtmetrics.css b/non-puppet/qtmetrics2/styles/qtmetrics.css
index 58bcee3..f61a25e 100644
--- a/non-puppet/qtmetrics2/styles/qtmetrics.css
+++ b/non-puppet/qtmetrics2/styles/qtmetrics.css
@@ -35,7 +35,7 @@
/**
* Qt Metrics style sheet
- * @since 03-08-2015
+ * @since 05-08-2015
* @author Juha Sippola
*/
@@ -114,6 +114,9 @@
#link_loading .progress-bar {
width: 100%;
}
+.data_loading .progress-bar {
+ width: 100%;
+}
/*
* Animation shown while loading data in autocomplete input field
diff --git a/non-puppet/qtmetrics2/templates/about.html b/non-puppet/qtmetrics2/templates/about.html
index c15320d..cb92979 100644
--- a/non-puppet/qtmetrics2/templates/about.html
+++ b/non-puppet/qtmetrics2/templates/about.html
@@ -34,7 +34,7 @@
/**
* About window content
- * @since 03-08-2015
+ * @since 14-08-2015
* @author Juha Sippola
*/
@@ -43,4 +43,4 @@
<p>This is Qt Metrics revision 2 with redesigned UI and database.</p>
<p>These pages are still <strong>under construction</strong> and therefore the views and functionality is limited.</p>
<p>See the <a href="https://wiki.qt.io/Qt_Metrics_2_Backlog" target="_blank">backlog</a> for development items currently identified or in progress.</p>
-<p><small>Version 0.18 (03-Aug-2015)</small></p>
+<p><small>Version 0.19 (14-Aug-2015)</small></p>
diff --git a/non-puppet/qtmetrics2/templates/testset_project.html b/non-puppet/qtmetrics2/templates/testset_project.html
index da12f35..276852b 100644
--- a/non-puppet/qtmetrics2/templates/testset_project.html
+++ b/non-puppet/qtmetrics2/templates/testset_project.html
@@ -34,7 +34,7 @@
/**
* Testset project page
- * @since 03-08-2015
+ * @since 05-08-2015
* @author Juha Sippola
*/
@@ -42,9 +42,6 @@
{% include "header.html" %}
-{# Failed/passed bar area size in px #}
-{% set BAR_AREA = 60 %}
-
<ol class="breadcrumb">
{% for link in breadcrumb %}
<li><a href="{{ link.link }}">{{ link.name }}</a></li>
@@ -57,16 +54,10 @@
<div class="col-sm-12 col-md-12 main">
-{# Check if any runs available #}
-{% set runsAvailable = 0 %}
-{% for run in confBuilds %}
-{% set runsAvailable = 1 %}
-{% endfor %}
-
{##### Title #####}
<h1 class="page-header">
-{{ project }}
+<span id="project">{{ project }}</span>
<button type="button" class="btn btn-xs btn-info" data-toggle="collapse" data-target="#info" aria-expanded="false" aria-controls="info">
<span class="glyphicon glyphicon-info-sign"></span>
</button>
@@ -86,249 +77,40 @@ in any configuration across all branches.</li>
and their configuration in <strong>{{ masterProject }} {{ masterState }}</strong> builds
<ul>
<li>log file: <span class="glyphicon glyphicon-file blue"></span> = link to {{ masterProject }} {{ masterState }} build log file</li>
-<li>results: <button type="button" class="btn btn-xs btn-success"><span class="badge">n</span></button> = all n testsets passed,
+<li>results: <button type="button" class="btn btn-xs btn-success" disabled="disabled"><span class="badge">n</span></button> = all n testsets passed,
<button type="button" class="btn btn-xs btn-danger"><span class="badge">n</span></button> = n testsets failed</li>
</ul>
-<li>Details are available as tooltip on result icon</li>
</ul>
</div>
</div>
-{% if runsAvailable %}
-
{##### Latest Status #####}
+<div id="testset_project_data_latest">
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="panel-title bold">Latest Status</h4>
</div>
-
-{# Get branches #}
-{% set branches = [] %}
-{% for run in latestTestsetRuns %}
-{% if run.branch not in branches %}
-{% set branches = branches|merge([run.branch]) %}
-{% endif %}
-{% endfor %}
-
-<div class="panel-body">
-<div class="table-responsive">
-<table class="table table-striped">
-<thead>
-<tr>
-<th class="rightBorder">testset project</th>
-{% for branch in branches %}
-<th class="center">{{ branch }}<br>
-<small>failed <span class ="gray">(total)</span></small>
-</th>
-<th class="showInLargeDisplay"></th>
-{% endfor %}
-</tr>
-</thead>
-<tbody>
-{# Calculate max failed result count for the bar #}
-{% set maxCount = 1 %}
-{% for run in latestTestsetRuns %}
-{% if run.failed > maxCount %}
-{% set maxCount = run.failed %}
-{% endif %}
-{% endfor %}
-
-<tr>
-{# Project name #}
-<td class="rightBorder">{{ project }}</td>
-
-{# Result (by branch) #}
-{% for branch in branches %}
-{% for run in latestTestsetRuns if project == run.project and branch == run.branch %}
-
-{# Show results #}
-{% set failed = run.failed %}
-{% set passed = run.passed %}
-{% set total = passed + failed %}
-<td class="center">{{ failed }}<span class ="gray"> ({{ total }})</span></td>
-
-{# Show results as bars (scaled to BAR_AREA px) #}
-{% set failedBar = ((BAR_AREA/maxCount) * failed)|round(0, 'floor') %}
-{% if (failed > 0) and (failedBar == 0) %}
-{% set failedBar = 1 %}
-{% endif %}
-{% if failed == 0 %}
-{% set failed = '' %}
-{% endif %}
-{% if (passed > 0) and (failed == 0) %}
-{% set passedBar = BAR_AREA %}
-{% else %}
-{% set passed = '' %}
-{% endif %}
-<td class="center showInLargeDisplay">
-<div>
-<div class="floatLeft redBackground" style="width: {{ failedBar }}px">{{ failed }}</div>
-<div class="floatLeft greenBackground" style="width: {{ passedBar }}px">{{ passed }}</div>
</div>
-</td>
-{% else %}{# for #}
-<td></td>
-{% endfor %}
-{% endfor %}
-</tr>
-</tbody>
-</table>
-</div> {# .table-responsive #}
-</div> {# .panel-body #}
-</div> {# .panel... #}
+<div class="progress data_loading">
+<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
+</div>
+</div>
+</div> {# testset_project_data_latest #}
{##### Results in Branches #####}
+<div id="testset_project_data_results">
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="panel-title bold">Results in Branches</h4>
</div>
</div>
-
-{# Get branches #}
-{% set branches = [] %}
-{% for run in projectRuns %}
-{% if run.getBranchName not in branches %}
-{% set branches = branches|merge([run.getBranchName]) %}
-{% endif %}
-{% endfor %}
-
-{# Loop all the branches #}
-{% for branch in branches %}
-
-{# Get all build keys, dates and log links #}
-{% set buildKey = '' %}
-{% set buildKeys = [] %}
-{% set dates = [] %}
-{% set logLinks = [] %}
-{% for run in projectRuns %}
-{% if run.getBranchName == branch %}
-{% if buildKey != run.getBuildKey %}
-{% set buildKey = run.getBuildKey %}
-{% set buildKeys = buildKeys|merge([run.getBuildKey]) %}
-{% set dates = dates|merge([run.getTimestamp]) %}
-{% set logLinks = logLinks|merge([run.getLogLink]) %}
-{% endif %}
-{% endif %}
-{% endfor %}
-
-{# Check if testsets run for this branch #}
-{% set testsetBranch = 0 %}
-{% for run in confBuilds if run.branch == branch %}
-{% set testsetBranch = 1 %}
-{% endfor %}
-
-{# Show branch if testsets run for it #}
-{% if testsetBranch %}
-<div class="panel panel-info">
-<div class="panel-heading">
-<h4 class="panel-title bold">{{ branch }}</h4>
+<div class="progress data_loading">
+<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
</div>
-<div class="panel-body">
-<div class="table-responsive">
-<table class="table table-striped">
-<thead>
-<tr>
-<th class="bold rightBorder">{{ project }}</th>
-{% for key, buildKey in buildKeys %}
-<th class="center">
-{% if buildKey|length > 6 %}
-<span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ buildKey }}">{{ buildKey|slice(0, 4) }}...</span><br>
-{% else %}
-{{ buildKey }}<br>
-{% endif %}
-<span class="gray"><small>{{ dates[key]|date("m-d") }}</small></span><br>
-<a href="{{ logLinks[key] }}" target="_blank"><span class="glyphicon glyphicon-file"></span></a>
-</th>
-{% endfor %}
-</tr>
-</thead>
-<tbody>
-{% set confPrev = '' %}
-{% set buildKeyIndexPrinted = -1 %}
-{% set buildKeyFound = 0 %}
-{% for run in confBuilds if run.branch == branch %}
-
-{# New row for each conf #}
-{% if confPrev != run.conf %}
-{# Close previous row #}
-{% if confPrev != '' %}
-{# Fill empty cells at the end of the row #}
-{% for key, buildKey in buildKeys %}
-{% if key > buildKeyIndexPrinted %}
-<td></td>
-{% endif %}
-{% endfor %}
-</tr>
-{% endif %}
-<tr>
-{% set link = confRoute ~ '/' ~ run.conf|url_encode ~ '/' ~ project|url_encode %}
-<td class="rightBorder"><a href="{{ link }}"><small>{{ run.conf }}</small></a></td>
-{% set buildKeyIndexPrinted = -1 %}
-{% endif %}
-
-{# Result per build key #}
-{% set buildKeyFound = 0 %}
-{% for key, buildKey in buildKeys %}
-{# Print each column only once (checked based on column index key and buildKeyFound flag) #}
-{% if key > buildKeyIndexPrinted and not buildKeyFound %}
-{% if buildKey == run.buildKey %}
-{# Print results #}
-<td class="center">
-{% if (run.failed + run.ifailed) > 0 %}
-<button type="button" class="btn btn-xs btn-danger clickOnTouch" data-toggle="tooltip" data-placement="top" data-html="true"
-title="<table>
-<tr><th>Build key: </th><td>{{ buildKey }}</td></tr>
-<tr><th>Configuration: </th><td>{{ run.conf }}</td></tr>
-<tr><th>Testsets passed: </th><td>{{ run.passed }}</td></tr>
-<tr><th>Testsets passed (insignificant): </th><td>{{ run.ipassed }}</td></tr>
-<tr><th>Testsets failed: </th><td>{{ run.failed }}</td></tr>
-<tr><th>Testsets failed (insignificant): </th><td>{{ run.ifailed }}</td></tr></table>">
-<span class="badge">{{ run.failed + run.ifailed }}</span></button>
-{% elseif (run.passed + run.ipassed) > 0 %}
-<button type="button" class="btn btn-xs btn-success clickOnTouch" data-toggle="tooltip" data-placement="top" data-html="true"
-title="<table>
-<tr><th>Build key: </th><td>{{ buildKey }}</td></tr>
-<tr><th>Configuration: </th><td>{{ run.conf }}</td></tr>
-<tr><th>Testsets passed: </th><td>{{ run.passed }}</td></tr>
-<tr><th>Testsets passed (insignificant): </th><td>{{ run.ipassed }}</td></tr>
-<tr><th>Testsets failed: </th><td>{{ run.failed }}</td></tr>
-<tr><th>Testsets failed (insignificant): </th><td>{{ run.ifailed }}</td></tr></table>">
-<span class="badge"><small>{{ run.passed + run.ipassed }}</small></span></button>
-{% endif %}
-</td>
-{% set buildKeyFound = 1 %}
-{% else %}
-{# Print empty cell #}
-<td></td>
-{% endif %}
-{% set buildKeyIndexPrinted = key %}
-{% endif %}
-{% endfor %}
-{% set confPrev = run.conf %}
-{% endfor %}
-
-{# Close last row (also fill empty cells at the end of the row) #}
-{% for key, buildKey in buildKeys %}
-{% if key > buildKeyIndexPrinted %}
-<td></td>
-{% endif %}
-{% endfor %}
-</tr>
-</tbody>
-</table>
-</div> {# .table-responsive #}
-</div> {# .panel-body #}
-</div> {# .panel... #}
-{% endif %}{# testsetBranch #}
-{% endfor %}{# branch #}
-
-{% else %}{# runsAvailable #}
-<div class="alert alert-danger" role="alert">
-No test result data available for project {{ project }}!
</div>
-{% endif %}{# runsAvailable #}
+</div> {# testset_project_data_results #}
</div> {# .col... #}
</div> {# .row #}
@@ -337,6 +119,6 @@ No test result data available for project {{ project }}!
{% include "footer.html" %}
{# Local scripts for this page #}
-<script src="scripts/tooltip.js"></script>
+<script src="scripts/ajax.js"></script>
{% include "close.html" %}
diff --git a/non-puppet/qtmetrics2/templates/testset_project_data_latest.html b/non-puppet/qtmetrics2/templates/testset_project_data_latest.html
new file mode 100644
index 0000000..26d8535
--- /dev/null
+++ b/non-puppet/qtmetrics2/templates/testset_project_data_latest.html
@@ -0,0 +1,136 @@
+{#
+#############################################################################
+##
+## Copyright (C) 2015 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Quality Assurance module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL21$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see http://www.qt.io/terms-conditions. For further
+## information use the contact form at http://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 or version 3 as published by the Free
+## Software Foundation and appearing in the file LICENSE.LGPLv21 and
+## LICENSE.LGPLv3 included in the packaging of this file. Please review the
+## following information to ensure the GNU Lesser General Public License
+## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## As a special exception, The Qt Company gives you certain additional
+## rights. These rights are described in The Qt Company LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+/**
+ * Testset project latest data
+ * @since 04-08-2015
+ * @author Juha Sippola
+ */
+
+#}
+
+{# Failed/passed bar area size in px #}
+{% set BAR_AREA = 60 %}
+
+{# Check if any runs available #}
+{% set runsAvailable = 0 %}
+{% for run in latestTestsetRuns %}
+{% set runsAvailable = 1 %}
+{% endfor %}
+
+{% if runsAvailable %}
+
+{##### Latest Status #####}
+
+<div class="panel panel-primary">
+<div class="panel-heading">
+<h4 class="panel-title bold">Latest Status</h4>
+</div>
+
+{# Get branches #}
+{% set branches = [] %}
+{% for run in latestTestsetRuns %}
+{% if run.branch not in branches %}
+{% set branches = branches|merge([run.branch]) %}
+{% endif %}
+{% endfor %}
+
+<div class="panel-body">
+<div class="table-responsive">
+<table class="table table-striped">
+<thead>
+<tr>
+<th class="rightBorder">testset project</th>
+{% for branch in branches %}
+<th class="center">{{ branch }}<br>
+<small>failed <span class ="gray">(total)</span></small>
+</th>
+<th class="showInLargeDisplay"></th>
+{% endfor %}
+</tr>
+</thead>
+<tbody>
+{# Calculate max failed result count for the bar #}
+{% set maxCount = 1 %}
+{% for run in latestTestsetRuns %}
+{% if run.failed > maxCount %}
+{% set maxCount = run.failed %}
+{% endif %}
+{% endfor %}
+
+<tr>
+{# Project name #}
+<td class="rightBorder">{{ project }}</td>
+
+{# Result (by branch) #}
+{% for branch in branches %}
+{% for run in latestTestsetRuns if project == run.project and branch == run.branch %}
+
+{# Show results #}
+{% set failed = run.failed %}
+{% set passed = run.passed %}
+{% set total = passed + failed %}
+<td class="center">{{ failed }}<span class ="gray"> ({{ total }})</span></td>
+
+{# Show results as bars (scaled to BAR_AREA px) #}
+{% set failedBar = ((BAR_AREA/maxCount) * failed)|round(0, 'floor') %}
+{% if (failed > 0) and (failedBar == 0) %}
+{% set failedBar = 1 %}
+{% endif %}
+{% if failed == 0 %}
+{% set failed = '' %}
+{% endif %}
+{% if (passed > 0) and (failed == 0) %}
+{% set passedBar = BAR_AREA %}
+{% else %}
+{% set passed = '' %}
+{% endif %}
+<td class="center showInLargeDisplay">
+<div>
+<div class="floatLeft redBackground" style="width: {{ failedBar }}px">{{ failed }}</div>
+<div class="floatLeft greenBackground" style="width: {{ passedBar }}px">{{ passed }}</div>
+</div>
+</td>
+{% else %}{# for #}
+<td></td>
+{% endfor %}
+{% endfor %}
+</tr>
+</tbody>
+</table>
+</div> {# .table-responsive #}
+</div> {# .panel-body #}
+</div> {# .panel... #}
+
+{% endif %}{# runsAvailable #}
diff --git a/non-puppet/qtmetrics2/templates/testset_project_data_results.html b/non-puppet/qtmetrics2/templates/testset_project_data_results.html
new file mode 100644
index 0000000..e953e29
--- /dev/null
+++ b/non-puppet/qtmetrics2/templates/testset_project_data_results.html
@@ -0,0 +1,188 @@
+{#
+#############################################################################
+##
+## Copyright (C) 2015 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Quality Assurance module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL21$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see http://www.qt.io/terms-conditions. For further
+## information use the contact form at http://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 or version 3 as published by the Free
+## Software Foundation and appearing in the file LICENSE.LGPLv21 and
+## LICENSE.LGPLv3 included in the packaging of this file. Please review the
+## following information to ensure the GNU Lesser General Public License
+## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## As a special exception, The Qt Company gives you certain additional
+## rights. These rights are described in The Qt Company LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+/**
+ * Testset project results data
+ * @since 04-08-2015
+ * @author Juha Sippola
+ */
+
+#}
+
+{# Check if any runs available #}
+{% set runsAvailable = 0 %}
+{% for run in confBuilds %}
+{% set runsAvailable = 1 %}
+{% endfor %}
+
+{% if runsAvailable %}
+
+{##### Results in Branches #####}
+
+<div class="panel panel-primary">
+<div class="panel-heading">
+<h4 class="panel-title bold">Results in Branches</h4>
+</div>
+</div>
+
+{# Get branches #}
+{% set branches = [] %}
+{% for run in projectRuns %}
+{% if run.getBranchName not in branches %}
+{% set branches = branches|merge([run.getBranchName]) %}
+{% endif %}
+{% endfor %}
+
+{# Loop all the branches #}
+{% for branch in branches %}
+
+{# Get all build keys, dates and log links #}
+{% set buildKey = '' %}
+{% set buildKeys = [] %}
+{% set dates = [] %}
+{% set logLinks = [] %}
+{% for run in projectRuns %}
+{% if run.getBranchName == branch %}
+{% if buildKey != run.getBuildKey %}
+{% set buildKey = run.getBuildKey %}
+{% set buildKeys = buildKeys|merge([run.getBuildKey]) %}
+{% set dates = dates|merge([run.getTimestamp]) %}
+{% set logLinks = logLinks|merge([run.getLogLink]) %}
+{% endif %}
+{% endif %}
+{% endfor %}
+
+{# Check if testsets run for this branch #}
+{% set testsetBranch = 0 %}
+{% for run in confBuilds if run.branch == branch %}
+{% set testsetBranch = 1 %}
+{% endfor %}
+
+{# Show branch if testsets run for it #}
+{% if testsetBranch %}
+<div class="panel panel-info">
+<div class="panel-heading">
+<h4 class="panel-title bold">{{ branch }}</h4>
+</div>
+<div class="panel-body">
+<div class="table-responsive">
+<table class="table table-striped">
+<thead>
+<tr>
+<th class="bold rightBorder">{{ project }}</th>
+{% for key, buildKey in buildKeys %}
+<th class="center">
+{% if buildKey|length > 6 %}
+<span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ buildKey }}">{{ buildKey|slice(0, 4) }}...</span><br>
+{% else %}
+{{ buildKey }}<br>
+{% endif %}
+<span class="gray"><small>{{ dates[key]|date("m-d") }}</small></span><br>
+<a href="{{ logLinks[key] }}" target="_blank"><span class="glyphicon glyphicon-file"></span></a>
+</th>
+{% endfor %}
+</tr>
+</thead>
+<tbody>
+{% set confPrev = '' %}
+{% set buildKeyIndexPrinted = -1 %}
+{% set buildKeyFound = 0 %}
+{% for run in confBuilds if run.branch == branch %}
+
+{# New row for each conf #}
+{% if confPrev != run.conf %}
+{# Close previous row #}
+{% if confPrev != '' %}
+{# Fill empty cells at the end of the row #}
+{% for key, buildKey in buildKeys %}
+{% if key > buildKeyIndexPrinted %}
+<td></td>
+{% endif %}
+{% endfor %}
+</tr>
+{% endif %}
+<tr>
+{% set link = confRoute ~ '/' ~ run.conf|url_encode ~ '/' ~ project|url_encode %}
+<td class="rightBorder"><a href="{{ link }}"><small>{{ run.conf }}</small></a></td>
+{% set buildKeyIndexPrinted = -1 %}
+{% endif %}
+
+{# Result per build key #}
+{% set buildKeyFound = 0 %}
+{% for key, buildKey in buildKeys %}
+{# Print each column only once (checked based on column index key and buildKeyFound flag) #}
+{% if key > buildKeyIndexPrinted and not buildKeyFound %}
+{% if buildKey == run.buildKey %}
+{# Print results #}
+<td class="center">
+{% if (run.failed + run.ifailed) > 0 %}
+<button type="button" class="btn btn-xs btn-danger clickOnTouch" data-toggle="tooltip" data-placement="top" data-html="true"
+title="{{ run.failed + run.ifailed }} failed out of {{ run.failed + run.ifailed + run.passed + run.ipassed }}">
+<span class="badge"><small>{{ run.failed + run.ifailed }}</small></span></button>
+{% elseif (run.passed + run.ipassed) > 0 %}
+<button type="button" class="btn btn-xs btn-success" disabled="disabled">
+<span class="badge"><small>{{ run.passed + run.ipassed }}</small></span></button>
+{% endif %}
+</td>
+{% set buildKeyFound = 1 %}
+{% else %}
+{# Print empty cell #}
+<td></td>
+{% endif %}
+{% set buildKeyIndexPrinted = key %}
+{% endif %}
+{% endfor %}
+{% set confPrev = run.conf %}
+{% endfor %}
+
+{# Close last row (also fill empty cells at the end of the row) #}
+{% for key, buildKey in buildKeys %}
+{% if key > buildKeyIndexPrinted %}
+<td></td>
+{% endif %}
+{% endfor %}
+</tr>
+</tbody>
+</table>
+</div> {# .table-responsive #}
+</div> {# .panel-body #}
+</div> {# .panel... #}
+{% endif %}{# testsetBranch #}
+{% endfor %}{# branch #}
+
+{% else %}{# runsAvailable #}
+<div class="alert alert-danger" role="alert">
+No test result data available for project {{ project }}!
+</div>
+{% endif %}{# runsAvailable #}
diff --git a/non-puppet/qtmetrics2/templates/testsets_flaky.html b/non-puppet/qtmetrics2/templates/testsets_flaky.html
index 45d3ccf..bcd338e 100644
--- a/non-puppet/qtmetrics2/templates/testsets_flaky.html
+++ b/non-puppet/qtmetrics2/templates/testsets_flaky.html
@@ -34,7 +34,7 @@
/**
* Flaky testsets page
- * @since 03-08-2015
+ * @since 05-08-2015
* @author Juha Sippola
*/
@@ -42,15 +42,6 @@
{% include "header.html" %}
-{# Failed/passed bar area size in px #}
-{% set BAR_AREA = 120 %}
-
-{# testsets as Testset objects
-/**
- * @var Testset[] testsets
- */
-#}
-
<ol class="breadcrumb">
{% for link in breadcrumb %}
<li><a href="{{ link.link }}">{{ link.name }}</a></li>
@@ -88,61 +79,17 @@ the testset is flaky (during the last {{ lastDays }} days).</li>
{##### Flaky list #####}
+<div id="flaky_testsets_data">
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4>
</div>
-<div class="panel-body">
-<div class="table-responsive">
-<table class="table table-striped">
-<thead>
-<tr>
-<th>testset</th>
-<th>project</th>
-<th class="leftBorder center">flaky <span class ="gray">(total)</span></th>
-<th class="showInLargeDisplay">flaky</th>
-</tr>
-</thead>
-<tbody>
-{# Calculate max result count for the bar #}
-{% set maxCount = 1 %}
-{% for testset in testsets %}
-{% if testset.getTestsetFlakyCounts.flaky > maxCount %}
-{% set maxCount = testset.getTestsetFlakyCounts.flaky %}
-{% endif %}
-{% endfor %}
-
-{# Print testsets #}
-{% for testset in testsets %}
-<tr>
-{# Testset name #}
-<td><a href="{{ testsetRoute }}/{{ testset.getName|url_encode }}/{{ testset.getProjectName|url_encode }}">{{ testset.getName }}</a></td>
-
-{# Project name #}
-<td>{{ testset.getProjectName }}</td>
-
-{# Show results as numbers #}
-{% set flaky = testset.getTestsetFlakyCounts.flaky %}
-{% set total = testset.getTestsetFlakyCounts.total %}
-<td class="leftBorder center">{{ flaky }}<span class ="gray"> ({{ total }})</span></td>
-
-{# Show results as bars (scaled to BAR_AREA px) #}
-{% set flakyBar = ((BAR_AREA/maxCount)*flaky)|round(0, 'floor') %}
-{% if (flaky > 0) and (flakyBar == 0) %}
-{% set flakyBar = 1 %}
-{% endif %}
-<td class="center showInLargeDisplay">
-<div>
-<div class="floatLeft redBackground" style="width: {{ flakyBar }}px">&nbsp;</div>
</div>
-</td>
-</tr>
-{% endfor %}{# testset #}
-</tbody>
-</table>
-</div> {# .table-responsive #}
-</div> {# .panel-body #}
-</div> {# .panel... #}
+<div class="progress data_loading">
+<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
+</div>
+</div>
+</div> {# flaky_testsets_data #}
</div> {# .col... #}
</div> {# .row #}
@@ -151,6 +98,6 @@ the testset is flaky (during the last {{ lastDays }} days).</li>
{% include "footer.html" %}
{# Local scripts for this page #}
-{# (none) #}
+<script src="scripts/ajax.js"></script>
{% include "close.html" %}
diff --git a/non-puppet/qtmetrics2/templates/testsets_flaky_data.html b/non-puppet/qtmetrics2/templates/testsets_flaky_data.html
new file mode 100644
index 0000000..f091337
--- /dev/null
+++ b/non-puppet/qtmetrics2/templates/testsets_flaky_data.html
@@ -0,0 +1,108 @@
+{#
+#############################################################################
+##
+## Copyright (C) 2015 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Quality Assurance module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL21$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see http://www.qt.io/terms-conditions. For further
+## information use the contact form at http://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 or version 3 as published by the Free
+## Software Foundation and appearing in the file LICENSE.LGPLv21 and
+## LICENSE.LGPLv3 included in the packaging of this file. Please review the
+## following information to ensure the GNU Lesser General Public License
+## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## As a special exception, The Qt Company gives you certain additional
+## rights. These rights are described in The Qt Company LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+/**
+ * Flaky testsets data
+ * @since 05-08-2015
+ * @author Juha Sippola
+ */
+
+#}
+
+{# Failed/passed bar area size in px #}
+{% set BAR_AREA = 120 %}
+
+{# testsets as Testset objects
+/**
+ * @var Testset[] testsets
+ */
+#}
+
+{##### Flaky list #####}
+
+<div class="panel panel-primary">
+<div class="panel-heading">
+<h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4>
+</div>
+<div class="panel-body">
+<div class="table-responsive">
+<table class="table table-striped">
+<thead>
+<tr>
+<th>testset</th>
+<th>project</th>
+<th class="leftBorder center">flaky <span class ="gray">(total)</span></th>
+<th class="showInLargeDisplay">flaky</th>
+</tr>
+</thead>
+<tbody>
+{# Calculate max result count for the bar #}
+{% set maxCount = 1 %}
+{% for testset in testsets %}
+{% if testset.getTestsetFlakyCounts.flaky > maxCount %}
+{% set maxCount = testset.getTestsetFlakyCounts.flaky %}
+{% endif %}
+{% endfor %}
+
+{# Print testsets #}
+{% for testset in testsets %}
+<tr>
+{# Testset name #}
+<td><a href="{{ testsetRoute }}/{{ testset.getName|url_encode }}/{{ testset.getProjectName|url_encode }}">{{ testset.getName }}</a></td>
+
+{# Project name #}
+<td>{{ testset.getProjectName }}</td>
+
+{# Show results as numbers #}
+{% set flaky = testset.getTestsetFlakyCounts.flaky %}
+{% set total = testset.getTestsetFlakyCounts.total %}
+<td class="leftBorder center">{{ flaky }}<span class ="gray"> ({{ total }})</span></td>
+
+{# Show results as bars (scaled to BAR_AREA px) #}
+{% set flakyBar = ((BAR_AREA/maxCount)*flaky)|round(0, 'floor') %}
+{% if (flaky > 0) and (flakyBar == 0) %}
+{% set flakyBar = 1 %}
+{% endif %}
+<td class="center showInLargeDisplay">
+<div>
+<div class="floatLeft redBackground" style="width: {{ flakyBar }}px">&nbsp;</div>
+</div>
+</td>
+</tr>
+{% endfor %}{# testset #}
+</tbody>
+</table>
+</div> {# .table-responsive #}
+</div> {# .panel-body #}
+</div> {# .panel... #}
diff --git a/non-puppet/qtmetrics2/templates/testsets_top.html b/non-puppet/qtmetrics2/templates/testsets_top.html
index dde9f3e..568f434 100644
--- a/non-puppet/qtmetrics2/templates/testsets_top.html
+++ b/non-puppet/qtmetrics2/templates/testsets_top.html
@@ -34,7 +34,7 @@
/**
* Top failures (testsets) page
- * @since 03-08-2015
+ * @since 05-08-2015
* @author Juha Sippola
*/
@@ -42,15 +42,6 @@
{% include "header.html" %}
-{# Failed/passed bar area size in px #}
-{% set BAR_AREA = 120 %}
-
-{# testsets as Testset objects
-/**
- * @var Testset[] testsets
- */
-#}
-
<ol class="breadcrumb">
{% for link in breadcrumb %}
<li><a href="{{ link.link }}">{{ link.name }}</a></li>
@@ -90,78 +81,17 @@ builds where it failed during the last {{ lastDays }} days.</li>
{##### Top list #####}
+<div id="testsets_top_data">
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4>
</div>
-<div class="panel-body">
-<div class="table-responsive">
-<table class="table table-striped">
-<thead>
-<tr>
-<th>testset</th>
-<th class="showInLargeDisplay">project</th>
-<th>latest result</th>
-<th class="leftBorder center">failed <span class ="gray">(total)</span></th>
-<th class="showInLargeDisplay">failed + passed</th>
-</tr>
-</thead>
-<tbody>
-{# Calculate max result count for the bar #}
-{% set maxCount = 1 %}
-{% for testset in testsets %}
-{% if (testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed) > maxCount %}
-{% set maxCount = testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed %}
-{% endif %}
-{% endfor %}
-
-{# Print testsets #}
-{% for testset in testsets %}
-<tr>
-{# Testset name #}
-<td><a href="{{ testsetRoute }}/{{ testset.getName|url_encode }}/{{ testset.getProjectName|url_encode }}">{{ testset.getName }}</a></td>
-
-{# Project name #}
-<td class="showInLargeDisplay">{{ testset.getProjectName }}</td>
-
-{# Testset status according to the latest build results #}
-{% if testset.getStatus == constant('testsetRun::RESULT_SUCCESS') %}
-{% set resultIcon = 'glyphicon glyphicon-ok green' %}
-{% elseif testset.getStatus == constant('testsetRun::RESULT_FAILURE') %}
-{% set resultIcon = 'glyphicon glyphicon-remove red' %}
-{% else %}
-{% set resultIcon = '' %}
-{% endif %}
-<td><span class="spaceHorizontal {{ resultIcon }}"></span>{{ testset.getStatus }}</td>
-
-{# Show results as numbers #}
-{% set failed = testset.getTestsetResultCounts.failed %}
-{% set passed = testset.getTestsetResultCounts.passed %}
-{% set total = passed + failed %}
-<td class="leftBorder center">{{ failed }}<span class ="gray"> ({{ total }})</span></td>
-
-{# Show results as bars (scaled to BAR_AREA px) #}
-{% set passedBar = ((BAR_AREA/maxCount) * passed)|round(0, 'floor') %}
-{% if (passed > 0) and (passedBar == 0) %}
-{% set passedBar = 1 %}
-{% endif %}
-{% set failedBar = ((BAR_AREA/maxCount)*failed)|round(0, 'floor') %}
-{% if (failed > 0) and (failedBar == 0) %}
-{% set failedBar = 1 %}
-{% endif %}
-<td class="center showInLargeDisplay">
-<div>
-<div class="floatLeft redBackground" style="width: {{ failedBar }}px">&nbsp;</div>
-<div class="floatLeft greenBackground" style="width: {{ passedBar }}px">&nbsp;</div>
</div>
-</td>
-</tr>
-{% endfor %}{# testset #}
-</tbody>
-</table>
-</div> {# .table-responsive #}
-</div> {# .panel-body #}
-</div> {# .panel... #}
+<div class="progress data_loading">
+<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
+</div>
+</div>
+</div> {# testsets_top_data #}
</div> {# .col... #}
</div> {# .row #}
@@ -170,6 +100,6 @@ builds where it failed during the last {{ lastDays }} days.</li>
{% include "footer.html" %}
{# Local scripts for this page #}
-{# (none) #}
+<script src="scripts/ajax.js"></script>
{% include "close.html" %}
diff --git a/non-puppet/qtmetrics2/templates/testsets_top_data.html b/non-puppet/qtmetrics2/templates/testsets_top_data.html
new file mode 100644
index 0000000..a4e70a0
--- /dev/null
+++ b/non-puppet/qtmetrics2/templates/testsets_top_data.html
@@ -0,0 +1,125 @@
+{#
+#############################################################################
+##
+## Copyright (C) 2015 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Quality Assurance module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL21$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see http://www.qt.io/terms-conditions. For further
+## information use the contact form at http://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 or version 3 as published by the Free
+## Software Foundation and appearing in the file LICENSE.LGPLv21 and
+## LICENSE.LGPLv3 included in the packaging of this file. Please review the
+## following information to ensure the GNU Lesser General Public License
+## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## As a special exception, The Qt Company gives you certain additional
+## rights. These rights are described in The Qt Company LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+/**
+ * Top failures (testsets) data
+ * @since 04-08-2015
+ * @author Juha Sippola
+ */
+
+#}
+
+{# Failed/passed bar area size in px #}
+{% set BAR_AREA = 120 %}
+
+{# testsets as Testset objects
+/**
+ * @var Testset[] testsets
+ */
+#}
+
+{##### Top list #####}
+
+<div class="panel panel-primary">
+<div class="panel-heading">
+<h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4>
+</div>
+<div class="panel-body">
+<div class="table-responsive">
+<table class="table table-striped">
+<thead>
+<tr>
+<th>testset</th>
+<th class="showInLargeDisplay">project</th>
+<th>latest result</th>
+<th class="leftBorder center">failed <span class ="gray">(total)</span></th>
+<th class="showInLargeDisplay">failed + passed</th>
+</tr>
+</thead>
+<tbody>
+{# Calculate max result count for the bar #}
+{% set maxCount = 1 %}
+{% for testset in testsets %}
+{% if (testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed) > maxCount %}
+{% set maxCount = testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed %}
+{% endif %}
+{% endfor %}
+
+{# Print testsets #}
+{% for testset in testsets %}
+<tr>
+{# Testset name #}
+<td><a href="{{ testsetRoute }}/{{ testset.getName|url_encode }}/{{ testset.getProjectName|url_encode }}">{{ testset.getName }}</a></td>
+
+{# Project name #}
+<td class="showInLargeDisplay">{{ testset.getProjectName }}</td>
+
+{# Testset status according to the latest build results #}
+{% if testset.getStatus == constant('testsetRun::RESULT_SUCCESS') %}
+{% set resultIcon = 'glyphicon glyphicon-ok green' %}
+{% elseif testset.getStatus == constant('testsetRun::RESULT_FAILURE') %}
+{% set resultIcon = 'glyphicon glyphicon-remove red' %}
+{% else %}
+{% set resultIcon = '' %}
+{% endif %}
+<td><span class="spaceHorizontal {{ resultIcon }}"></span>{{ testset.getStatus }}</td>
+
+{# Show results as numbers #}
+{% set failed = testset.getTestsetResultCounts.failed %}
+{% set passed = testset.getTestsetResultCounts.passed %}
+{% set total = passed + failed %}
+<td class="leftBorder center">{{ failed }}<span class ="gray"> ({{ total }})</span></td>
+
+{# Show results as bars (scaled to BAR_AREA px) #}
+{% set passedBar = ((BAR_AREA/maxCount) * passed)|round(0, 'floor') %}
+{% if (passed > 0) and (passedBar == 0) %}
+{% set passedBar = 1 %}
+{% endif %}
+{% set failedBar = ((BAR_AREA/maxCount)*failed)|round(0, 'floor') %}
+{% if (failed > 0) and (failedBar == 0) %}
+{% set failedBar = 1 %}
+{% endif %}
+<td class="center showInLargeDisplay">
+<div>
+<div class="floatLeft redBackground" style="width: {{ failedBar }}px">&nbsp;</div>
+<div class="floatLeft greenBackground" style="width: {{ passedBar }}px">&nbsp;</div>
+</div>
+</td>
+</tr>
+{% endfor %}{# testset #}
+</tbody>
+</table>
+</div> {# .table-responsive #}
+</div> {# .panel-body #}
+</div> {# .panel... #}