Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updating to Genshi templates, and bumping version to 0.2.

  • Loading branch information...
commit 6fc87e3baf6b4bba70ac5ecfc3705d6c36802b20 1 parent 6646e5a
@mrjbq7 authored
View
4 setup.py
@@ -3,7 +3,7 @@
from setuptools import setup, find_packages
PACKAGE = 'TracStats'
-VERSION = '0.1'
+VERSION = '0.2'
setup(
name=PACKAGE, version=VERSION,
@@ -15,7 +15,7 @@
'htdocs/*.png',
'htdocs/*.gif',
'htdocs/*.js',
- 'templates/*.cs'
+ 'templates/*.html'
]
},
entry_points = {
View
405 tracstats/templates/code.cs
@@ -1,405 +0,0 @@
-<?cs include "header.cs"?>
-<?cs include "macros.cs"?>
-
-<?cs include "nav.cs"?>
-
-<div id="content" class="wiki">
-
-<h1>Statistics - Source</h1>
-
-<table>
-<?cs if:stats.author ?>
-<tr><td width="150">Author<td align="right"><?cs var:stats.author ?></tr>
-<?cs /if ?>
-<tr><td width="150">Head Revision<td align="right"><?cs var:stats.code.maxrev ?></tr>
-<tr><td width="150">First revision<td align="right"><?cs var:stats.code.mintime ?></tr>
-<tr><td width="150">Last revision<td align="right"><?cs var:stats.code.maxtime ?></tr>
-<tr><td width="150">Repository age<td align="right"><?cs var:stats.code.age ?></tr>
-<tr><td width="150">Developers<td align="right"><?cs var:stats.code.developers ?></tr>
-<tr><td width="150">Commits<td align="right"><?cs var:stats.code.commits ?></tr>
-<tr><td width="150">Commits-per-year<td align="right"><?cs var:stats.code.commitsperyear ?></tr>
-<tr><td width="150">Commits-per-month<td align="right"><?cs var:stats.code.commitspermonth ?></tr>
-<tr><td width="150">Commits-per-day<td align="right"><?cs var:stats.code.commitsperday ?></tr>
-<tr><td width="150">Commits-per-hour<td align="right"><?cs var:stats.code.commitsperhour ?></tr>
-<tr><td width="150">Average log entry<td align="right"><?cs var:stats.code.logentry ?></tr>
-<tr><td width="150">Average changes<td align="right"><?cs var:stats.code.changes ?></tr>
-</table>
-
-<?cs if:len(stats.code.totalfiles) > 0 ?>
-<br>
-
-<h2>Total Files</h2>
-
-<div id="totalfiles" style="width:600px;height:300px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { mode: "time", timeformat: "%b %y" },
- colors: [ "#afd8f8" ],
- };
-
- var d = [<?cs
- each:stat = stats.code.totalfiles ?><?cs
- set:last = name(stat) == len(stats.code.totalfiles) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#totalfiles"), [ d ], options);
-});
-</script>
-<?cs /if ?>
-
-<br>
-
-<h2>Commits by time</h2>
-
-<div id="totalcommits" style="width:600px;height:300px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { mode: "time", timeformat: "%b %y" },
- };
-
- var d = [<?cs
- each:stat = stats.code.totalcommits ?><?cs
- set:last = name(stat) == len(stats.code.totalcommits) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#totalcommits"), [ d ], options);
-});
-</script>
-
-<br>
-
-<h2>Commits by author</h2>
-
-<table id="commitsbyauthor" class="tablesorter">
-<thead>
-<tr>
- <th>Author
- <th>Commits
- <th>Rate
- <th>Changes
- <th>Paths
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.code.byauthors ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="100" align="right"><?cs var:stat.commits ?>
-<td width="100" align="right"><?cs var:stat.rate ?>
-<td width="100" align="right"><?cs var:stat.changes ?>
-<td width="100" align="right"><?cs var:stat.paths ?>
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#commitsbyauthor").tablesorter( {sortList: [[1,1]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Commits by month</h2>
-
-<div id="commitsbymonth" style="width:600px;height:200px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { mode: "time", timeformat: "%b %y" },
- colors: [ "#afd8f8" ],
- };
-
- var d = [<?cs
- each:stat = stats.code.bymonth ?><?cs
- set:last = name(stat) == len(stats.code.bymonth) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#commitsbymonth"), [ d ], options);
-});
-</script>
-
-<br>
-
-<h2>Commits by day of week</h2>
-
-<div id="commitsbyday" style="width:500px;height:200px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- grid: { tickColor: "white" },
- bars: { show: true, fill: true },
- xaxis: { ticks: [[0.5,"Sun"],[1.5,"Mon"],[2.5,"Tue"],[3.5,"Wed"],
- [4.5,"Thu"],[5.5,"Fri"],[6.5,"Sat"]] },
- colors: [ "#afd8f8" ],
- };
-
- var d = [<?cs
- each:stat = stats.code.byday ?><?cs
- set:last = name(stat) == len(stats.code.byday) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#commitsbyday"), [ d ], options);
-});
-
-</script>
-
-<br>
-
-<h2>Commits by hour of day</h2>
-
-<div id="commitsbyhour" style="width:500px;height:200px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { ticks: [[0.5,"00:00"],[2.5,"02:00"],
- [4.5,"04:00"],[6.5,"06:00"],
- [8.5,"08:00"],[10.5,"10:00"],
- [12.5,"12:00"],[14.5,"14:00"],
- [16.5,"16:00"],[18.5,"18:00"],
- [20.5,"20:00"],[22.5,"22:00"]] },
- colors: [ "#afd8f8" ],
- };
-
- var d = [<?cs
- each:stat = stats.code.byhour ?><?cs
- set:last = name(stat) == len(stats.code.byhour) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#commitsbyhour"), [ d ], options);
-});
-
-</script>
-
-<br>
-
-<h2>Recent commits</h2>
-
-<table>
-<?cs each:stat = stats.code.recent ?>
-<tr>
-<td width="50"><a href="<?cs var:stat.url ?>"><?cs var:stat.rev ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.author ?></a>
-<td width="350"><?cs var:stat.name ?>
-<td width="100" align="right"><?cs var:stat.time ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Activity by time</h2>
-
-<div id="totalchanges" style="width:600px;height:300px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true},
- xaxis: { mode: "time", timeformat: "%b %y" },
- };
-
- var d = [<?cs
- each:stat = stats.code.totalchanges ?><?cs
- set:last = name(stat) == len(stats.code.totalchanges) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#totalchanges"), [ d ], options);
-});
-</script>
-
-<br>
-
-<h2>Activity by author</h2>
-
-<table id="activitybyauthor" class="tablesorter">
-<thead>
-<tr>
- <th>Author
- <th>Commits
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.code.byauthors ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="420" align="right">
-<span id="<?cs var:stat.name ?>weeks">Loading...</span>
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- var values = [<?cs
- each:week = stat.weeks ?><?cs
- set:last = name(week) == len(stat.weeks) - #1 ?><?cs
- var:week.total ?><?cs if:!last ?>,<?cs /if ?><?cs
- /each ?>];
- $("#<?cs var:stat.name ?>weeks").sparkline(values, {
- type: "bar",
- barColor: "lightgray",
- barWidth: 7,
- });
- }
-);
-</script>
-</td>
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#activitybyauthor").tablesorter( {sortList: [[0,0]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Activity by project</h2>
-
-<table id="activitybyproject" class="tablesorter">
-<thead>
-<tr>
- <th>Project
- <th>Commits
- <th>Changes
- <th>Paths
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.code.byproject ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="100" align="right"><?cs var:stat.commits ?>
-<td width="100" align="right"><?cs var:stat.changes ?>
-<td width="100" align="right"><?cs var:stat.paths ?>
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#activitybyproject").tablesorter( {sortList: [[1,1]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Most active paths</h2>
-
-<table>
-<?cs each:stat = stats.code.bypaths ?>
-<tr>
-<td width="400"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="75" align="right"><?cs var:stat.count ?>
-<td width="75" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Most active files</h2>
-
-<table>
-<?cs each:stat = stats.code.byfiles ?>
-<tr>
-<td width="400"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="75" align="right"><?cs var:stat.count ?>
-<td width="75" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Activity by filetype</h2>
-
-<table>
-<?cs each:stat = stats.code.byfiletypes ?>
-<tr>
-<td width="150"><?cs var:stat.name ?>
-<td width="75" align="right"><?cs var:stat.count ?>
-<td width="75" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Activity by change type</h2>
-
-<table class="changetypes" cellspacing="0" cellpadding="0">
-<?cs each:stat = stats.code.bychangetypes ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td>
- <div style="border: 1px darkgray solid;">
- <?cs if:stat.adds > 0 ?><div class="add" style="float: left; height: 12px; width:<?cs var:stat.adds * 3 ?>px;">&nbsp;</div><?cs /if ?>
- <?cs if:stat.copies > 0 ?><div class="copy" style="float: left; height: 12px; width:<?cs var:stat.copies * 3 ?>px;">&nbsp;</div><?cs /if ?>
- <?cs if:stat.deletes > 0 ?><div class="delete" style="float: left; height: 12px; width:<?cs var:stat.deletes * 3 ?>px;">&nbsp;</div><?cs /if ?>
- <?cs if:stat.edits > 0 ?><div class="edit" style="float: left; height: 12px; width:<?cs var:stat.edits * 3 ?>px;">&nbsp;</div><?cs /if ?>
- <?cs if:stat.moves > 0 ?><div class="move" style="float: left; height: 12px; width:<?cs var:stat.moves * 3 ?>px;">&nbsp;</div><?cs /if ?>
- <div style="clear: both;"></div>
- </div>
-</tr>
-<?cs /each ?>
-</table>
-<div class="legend">
-<dl>
- <dt class="add"></dt><dd>added</dd>
- <dt class="copy"></dt><dd>copied</dd>
- <dt class="delete"></dt><dd>deleted</dd>
- <dt class="edit"></dt><dd>edited</dd>
- <dt class="move"></dt><dd>moved</dd>
-</dl>
-</div>
-
-<br>
-
-<h2>Commit cloud</h2>
-
-<div style="width:600px;">
-<?cs each:stat = stats.code.cloud ?>
-<span style="font-size: <?cs var:stat.size ?>"><?cs var:stat.word ?></span>
-<?cs /each ?>
-</div>
-
-<br>
-<br>
-
-</div>
-
-<?cs include "footer.cs"?>
-
View
395 tracstats/templates/code.html
@@ -0,0 +1,395 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+
+ <head>
+ <title>Code Stats <py:if test="author">(${author})</py:if></title>
+ </head>
+
+<body>
+<div id="content" class="wiki">
+
+<h1>Statistics - Code</h1>
+
+<table>
+<py:if test="author">
+<tr><td width="150">Author</td><td align="right">${author}</td></tr>
+</py:if>
+<tr><td width="150">Head Revision</td><td align="right">${maxrev}</td></tr>
+<tr><td width="150">First revision</td><td align="right">${mintime}</td></tr>
+<tr><td width="150">Last revision</td><td align="right">${maxtime}</td></tr>
+<tr><td width="150">Repository age</td><td align="right">${age}</td></tr>
+<tr><td width="150">Developers</td><td align="right">${developers}</td></tr>
+<tr><td width="150">Commits</td><td align="right">${commits}</td></tr>
+<tr><td width="150">Commits-per-year</td><td align="right">${commitsperyear}</td></tr>
+<tr><td width="150">Commits-per-month</td><td align="right">${commitspermonth}</td></tr>
+<tr><td width="150">Commits-per-day</td><td align="right">${commitsperday}</td></tr>
+<tr><td width="150">Commits-per-hour</td><td align="right">${commitsperhour}</td></tr>
+<tr><td width="150">Average log entry</td><td align="right">${logentry}</td></tr>
+<tr><td width="150">Average changes</td><td align="right">${changes}</td></tr>
+</table>
+
+<py:if test="totalfiles">
+<br />
+
+<h2>Total Files</h2>
+
+<div id="totalfiles" style="width:600px;height:300px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ colors: [ "#afd8f8" ],
+ };
+
+ var d = [<py:for each="stat in totalfiles">[${stat.x}, ${stat.y}]<py:if
+ test="stat != totalfiles[-1]">,</py:if></py:for>];
+
+ $.plot($("#totalfiles"), [ d ], options);
+});
+</script>
+</py:if>
+
+<br />
+
+<h2>Commits by time</h2>
+
+<div id="totalcommits" style="width:600px;height:300px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ };
+
+ var d = [<py:for each="stat in totalcommits">[${stat.x}, ${stat.y}]<py:if
+ test="stat != totalcommits[-1]">,</py:if></py:for>];
+
+ $.plot($("#totalcommits"), [ d ], options);
+});
+</script>
+
+<br />
+
+<h2>Commits by author</h2>
+
+<table id="commitsbyauthor" class="tablesorter">
+<thead>
+<tr>
+ <th>Author</th>
+ <th>Commits</th>
+ <th>Rate</th>
+ <th>Changes</th>
+ <th>Paths</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in byauthors">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="100" align="right">${stat.commits}</td>
+ <td width="100" align="right">${stat.rate}</td>
+ <td width="100" align="right">${stat.changes}</td>
+ <td width="100" align="right">${stat.paths}</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#commitsbyauthor").tablesorter( {sortList: [[1,1]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Commits by month</h2>
+
+<div id="commitsbymonth" style="width:600px;height:200px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ colors: [ "#afd8f8" ],
+ };
+
+ var d = [<py:for each="stat in bymonth">[${stat.x}, ${stat.y}]<py:if
+ test="stat != bymonth[-1]">,</py:if></py:for>];
+
+ $.plot($("#commitsbymonth"), [ d ], options);
+});
+</script>
+
+<br />
+
+<h2>Commits by day of week</h2>
+
+<div id="commitsbyday" style="width:500px;height:200px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ grid: { tickColor: "white" },
+ bars: { show: true, fill: true },
+ xaxis: { ticks: [[0.5,"Sun"],[1.5,"Mon"],[2.5,"Tue"],[3.5,"Wed"],
+ [4.5,"Thu"],[5.5,"Fri"],[6.5,"Sat"]] },
+ colors: [ "#afd8f8" ],
+ };
+
+ var d = [<py:for each="stat in byday">[${stat.x}, ${stat.y}]<py:if
+ test="stat != byday[-1]">,</py:if></py:for>];
+
+ $.plot($("#commitsbyday"), [ d ], options);
+});
+
+</script>
+
+<br />
+
+<h2>Commits by hour of day</h2>
+
+<div id="commitsbyhour" style="width:500px;height:200px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { ticks: [[0.5,"00:00"],[2.5,"02:00"],
+ [4.5,"04:00"],[6.5,"06:00"],
+ [8.5,"08:00"],[10.5,"10:00"],
+ [12.5,"12:00"],[14.5,"14:00"],
+ [16.5,"16:00"],[18.5,"18:00"],
+ [20.5,"20:00"],[22.5,"22:00"]] },
+ colors: [ "#afd8f8" ],
+ };
+
+ var d = [<py:for each="stat in byhour">[${stat.x}, ${stat.y}]<py:if
+ test="stat != byhour[-1]">,</py:if></py:for>];
+
+ $.plot($("#commitsbyhour"), [ d ], options);
+});
+
+</script>
+
+<br />
+
+<h2>Recent commits</h2>
+
+<table>
+<py:for each="stat in recent">
+<tr>
+ <td width="50"><a href="${stat.url}">${stat.rev}</a></td>
+ <td width="150"><a href="${stat.url2}">${stat.author}</a></td>
+ <td width="350">${stat.name}</td>
+ <td width="100" align="right">${stat.time}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Activity by time</h2>
+
+<div id="totalchanges" style="width:600px;height:300px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true},
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ };
+
+ var d = [<py:for each="stat in totalchanges">[${stat.x}, ${stat.y}]<py:if
+ test="stat != totalchanges[-1]">,</py:if></py:for>];
+
+ $.plot($("#totalchanges"), [ d ], options);
+});
+</script>
+
+<br />
+
+<h2>Activity by author</h2>
+
+<table id="activitybyauthor" class="tablesorter">
+<thead>
+<tr>
+ <th>Author</th>
+ <th>Commits</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in byauthors">
+<tr>
+<td width="150"><a href="${stat.url}">${stat.name}</a></td>
+<td width="420" align="right">
+<span id="${stat.name}weeks">Loading...</span>
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ var values = [<py:for each="week in stat.weeks">${week.total}<py:if
+ test="week != stat.weeks[-1]">,</py:if></py:for>];
+ $("#${stat.name}weeks").sparkline(values, {
+ type: "bar",
+ barColor: "lightgray",
+ barWidth: 7,
+ });
+ }
+);
+</script>
+</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#activitybyauthor").tablesorter( {sortList: [[0,0]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Activity by project</h2>
+
+<table id="activitybyproject" class="tablesorter">
+<thead>
+<tr>
+ <th>Project</th>
+ <th>Commits</th>
+ <th>Changes</th>
+ <th>Paths</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in byproject">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="100" align="right">${stat.commits}</td>
+ <td width="100" align="right">${stat.changes}</td>
+ <td width="100" align="right">${stat.paths}</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#activitybyproject").tablesorter( {sortList: [[1,1]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Most active paths</h2>
+
+<table>
+<py:for each="stat in bypaths">
+<tr>
+ <td width="400"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="75" align="right">${stat.count}</td>
+ <td width="75" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Most active files</h2>
+
+<table>
+<py:for each="stat in byfiles">
+<tr>
+ <td width="400"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="75" align="right">${stat.count}</td>
+ <td width="75" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Activity by filetype</h2>
+
+<table>
+<py:for each="stat in byfiletypes">
+<tr>
+ <td width="150">${stat.name}</td>
+ <td width="75" align="right">${stat.count}</td>
+ <td width="75" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Activity by change type</h2>
+
+<table class="changetypes" cellspacing="0" cellpadding="0">
+<py:for each="stat in bychangetypes">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+<td>
+ <div style="border: 1px darkgray solid;">
+ <div py:if="stat.adds" class="add" style="float: left; height: 12px; width:${stat.adds*3}px;">&nbsp;</div>
+ <div py:if="stat.copies" class="copy" style="float: left; height: 12px; width:${stat.copies*3}px;">&nbsp;</div>
+ <div py:if="stat.deletes" class="delete" style="float: left; height: 12px; width:${stat.deletes*3}px;">&nbsp;</div>
+ <div py:if="stat.edits" class="edit" style="float: left; height: 12px; width:${stat.edits*3}>px;">&nbsp;</div>
+ <div py:if="stat.moves" class="move" style="float: left; height: 12px; width:${stat.moves*3}px;">&nbsp;</div>
+ <div style="clear: both;"></div>
+ </div>
+</td>
+</tr>
+</py:for>
+</table>
+<div class="legend">
+<dl>
+ <dt class="add"></dt><dd>added</dd>
+ <dt class="copy"></dt><dd>copied</dd>
+ <dt class="delete"></dt><dd>deleted</dd>
+ <dt class="edit"></dt><dd>edited</dd>
+ <dt class="move"></dt><dd>moved</dd>
+</dl>
+</div>
+
+<br />
+
+<h2>Commit cloud</h2>
+
+<div style="width:600px;">
+<py:for each="stat in cloud">
+<span style="font-size: ${stat.size}">${stat.word}</span>
+</py:for>
+</div>
+
+<br />
+<br />
+
+</div>
+
+</body>
+</html>
+
View
11 tracstats/templates/nav.cs
@@ -1,11 +0,0 @@
-
-<div id="ctxtnav" class="nav">
- <h2>Stats Navigation</h2>
- <ul>
- <li><a href="/stats/code">Code</a></li>
- <li><a href="/stats/wiki">Wiki</a></li>
- <li class="last"><a href="/stats/tickets">Tickets</a></li>
- </ul>
- <hr />
-</div>
-
View
93 tracstats/templates/stats.cs
@@ -1,93 +0,0 @@
-<?cs include "header.cs"?>
-<?cs include "macros.cs"?>
-
-<?cs include "nav.cs"?>
-
-<div id="content" class="wiki">
-
-<h1>Statistics</h1>
-
-<table cellpadding="10">
-<tr><td colspan="2" align="center">
-<span id="weeks">Loading...</span><br>
-<img src="<?cs var:chrome.href ?>/stats/legend.png">
-</td></tr>
-<tr><td valign="middle">
-<img src="<?cs var:chrome.href ?>/stats/code.png" align="center" valign="middle"> <a href="/stats/code">Code</a><br><br>
-<img src="<?cs var:chrome.href ?>/stats/wiki.png" align="center" valign="middle"> <a href="/stats/wiki">Wiki</a><br><br>
-<img src="<?cs var:chrome.href ?>/stats/tickets.png" align="center" valign="middle"> <a href="/stats/tickets">Tickets</a>
-</td><td valign="middle" style="border-left: 1px lightgray solid;">
-<b><?cs var: stats.years ?></b> <font color="gray">years,</font>
-<b><?cs var: stats.days ?></b> <font color="gray">days,</font>
-<b><?cs var: stats.hours ?></b> <font color="gray">hours of development</font>
-<br><br>
-<b><?cs var: stats.authors ?></b> <font color="gray">authors,</font>
-<b><?cs var: stats.revisions ?></b> <font color="gray">revisions,</font>
-<br><br>
-<b><?cs var: stats.pages ?></b> <font color="gray">wiki pages, and</font>
-<br><br>
-<b><?cs var: stats.tickets ?></b> <font color="gray">tickets</font>
-</td></tr>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
-
- var values = [<?cs
- each:stat = stats.code.weeks ?><?cs
- set:last = name(stat) == len(stats.code.weeks) - #1 ?><?cs
- var:stat.total ?><?cs if:!last ?>,<?cs /if ?><?cs
- /each ?>];
- $("#weeks").sparkline(values, {
- type: "bar",
- barColor: "lightgray",
- barWidth: 7,
- });
- }
-);
-</script>
-
-<table style="padding: 10px;">
-<tr>
-<td colspan=3>
-<p><i>Recent activity (within last 30 days):</i></p>
-</tr>
-<tr>
-<td><b>Developers</b>
-<td><b>Projects</b>
-<td><b>Paths</b>
-</tr>
-<tr>
-
-<td width=150 valign="top">
-<ol>
-<?cs each:stat = stats.code.byauthors ?>
-<li><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a></li>
-<?cs /each ?>
-</ol>
-</td>
-
-<td width=150 valign="top">
-<ol>
-<?cs each:stat = stats.code.byproject ?>
-<li><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a></li>
-<?cs /each ?>
-</ol>
-</td>
-
-<td width=300 valign="top">
-<ol>
-<?cs each:stat = stats.code.bypaths ?>
-<li><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a></li>
-<?cs /each ?>
-</ol>
-</td>
-
-</tr>
-</table>
-
-</div>
-
-<?cs include "footer.cs"?>
-
View
100 tracstats/templates/stats.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+ <head>
+ <title>Stats <py:if test="author">(${author})</py:if></title>
+ </head>
+
+<body>
+
+<div id="content" class="wiki">
+
+<h1>Statistics</h1>
+
+<table cellpadding="10">
+<tr><td colspan="2" align="center">
+<span id="weeks">Loading...</span><br />
+<img src="${req.href.chrome('stats/legend.png')}" />
+</td></tr>
+<tr><td valign="middle">
+<img src="${req.href.chrome('stats/code.png')}" align="center" valign="middle" /> <a href="${req.href.stats('code')}">Code</a><br /><br />
+<img src="${req.href.chrome('stats/wiki.png')}" align="center" valign="middle" /> <a href="${req.href.stats('wiki')}">Wiki</a><br /><br />
+<img src="${req.href.chrome('stats/tickets.png')}" align="center" valign="middle" /> <a href="${req.href.stats('tickets')}">Tickets</a>
+</td><td valign="middle" style="border-left: 1px lightgray solid;">
+<b>${years}</b> <font color="gray">years,</font>
+<b>${days}</b> <font color="gray">days,</font>
+<b>${hours}</b> <font color="gray">hours of development</font>
+<br /><br />
+<b>${authors}</b> <font color="gray">authors,</font>
+<b>${revisions}</b> <font color="gray">revisions,</font>
+<br /><br />
+<b>${pages}</b> <font color="gray">wiki pages, and</font>
+<br /><br />
+<b>${tickets}</b> <font color="gray">tickets</font>
+</td></tr>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ var values = [<py:for each="week in weeks">${week.total}<py:if
+ test="week != weeks[-1]">,</py:if></py:for>];
+ $("#weeks").sparkline(values, {
+ type: "bar",
+ barColor: "lightgray",
+ barWidth: 7,
+ });
+ }
+);
+</script>
+
+<table style="padding: 10px;">
+<tr>
+<td colspan="3">
+ <p><i>Recent activity (within last 30 days):</i></p>
+</td>
+</tr>
+<tr>
+ <td><b>Developers</b></td>
+ <td><b>Projects</b></td>
+ <td><b>Paths</b></td>
+</tr>
+<tr>
+
+<td width="150" valign="top">
+<ol>
+<py:for each="stat in byauthors">
+<li><a href="${stat.url}">${stat.name}</a></li>
+</py:for>
+</ol>
+</td>
+
+<td width="150" valign="top">
+<ol>
+<py:for each="stat in byproject">
+<li><a href="${stat.url}">${stat.name}</a></li>
+</py:for>
+</ol>
+</td>
+
+<td width="300" valign="top">
+<ol>
+<py:for each="stat in bypaths">
+<li><a href="${stat.url}">${stat.name}</a></li>
+</py:for>
+</ol>
+</td>
+
+</tr>
+</table>
+
+</div>
+
+</body>
+</html>
+
View
186 tracstats/templates/tickets.cs
@@ -1,186 +0,0 @@
-<?cs include "header.cs"?>
-<?cs include "macros.cs"?>
-
-<?cs include "nav.cs"?>
-
-<div id="content" class="wiki">
-
-<h1>Statistics - Tickets</h1>
-
-<table>
-<?cs if:stats.author ?>
-<tr><td width="150">Author<td align="right"><?cs var:stats.author ?></tr>
-<?cs /if ?>
-<tr><td width="150">First ticket<td align="right"><?cs var:stats.tickets.mintime ?></tr>
-<tr><td width="150">Last ticket<td align="right"><?cs var:stats.tickets.maxtime ?></tr>
-<tr><td width="150">Ticket age<td align="right"><?cs var:stats.tickets.age ?></tr>
-<tr><td width="150">Reporters<td align="right"><?cs var:stats.tickets.reporters ?></tr>
-<tr><td width="150">Tickets<td align="right"><?cs var:stats.tickets.total ?></tr>
-<tr><td width="150">Tickets-per-year<td align="right"><?cs var:stats.tickets.peryear ?></tr>
-<tr><td width="150">Tickets-per-month<td align="right"><?cs var:stats.tickets.permonth ?></tr>
-<tr><td width="150">Tickets-per-day<td align="right"><?cs var:stats.tickets.perday ?></tr>
-<tr><td width="150">Tickets-per-hour<td align="right"><?cs var:stats.tickets.perhour ?></tr>
-</table>
-
-<?cs if:len(stats.tickets.history) > 0 ?>
-<br>
-
-<h2>Open Tickets</h2>
-
-<div id="opentickets" style="width:600px;height:300px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { mode: "time", timeformat: "%b %y" },
- colors: [ "#afd8f8", "#cb4b4b" ],
- };
-
- var d1 = [<?cs
- each:stat = stats.tickets.history ?><?cs
- set:last = name(stat) == len(stats.tickets.history) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.opened ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- var d2 = [<?cs
- each:stat = stats.tickets.history ?><?cs
- set:last = name(stat) == len(stats.tickets.history) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.assigned ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#opentickets"), [ d1, d2 ], options);
-});
-</script>
-<?cs /if ?>
-
-<br>
-
-<h2>Tickets by author</h2>
-
-<table id="ticketsbyauthor" class="tablesorter">
-<thead>
-<tr>
- <th>Author
- <th>Reports
- <th>Changes
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.tickets.byauthor ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="100" align="right"><?cs var:stat.reports ?>
-<td width="100" align="right"><?cs var:stat.changes ?>
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#ticketsbyauthor").tablesorter( {sortList: [[1,1]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Tickets by component</h2>
-
-<table id="ticketsbycomponent" class="tablesorter">
-<thead>
-<tr>
- <th>Component
- <th>Open
- <th>Total
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.tickets.bycomponent ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="100" align="right"><?cs var:stat.open ?>
-<td width="100" align="right"><?cs var:stat.total ?>
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#ticketsbycomponent").tablesorter( {sortList: [[1,1]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Most active tickets</h2>
-
-<table>
-<?cs each:stat = stats.tickets.active ?>
-<tr>
-<td width="50"><a href="<?cs var:stat.url ?>"><?cs var:stat.id ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.component ?></a>
-<td width="350"><?cs var:stat.name ?>
-<td width="75" align="right"><?cs var:stat.count ?>
-<td width="75" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Oldest open tickets</h2>
-
-<table>
-<?cs each:stat = stats.tickets.oldest ?>
-<tr>
-<td width="50"><a href="<?cs var:stat.url ?>"><?cs var:stat.id ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.component ?></a>
-<td width="350"><?cs var:stat.name ?>
-<td width="100" align="right"><?cs var:stat.time ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Latest tickets reported</h2>
-
-<table>
-<?cs each:stat = stats.tickets.newest ?>
-<tr>
-<td width="50"><a href="<?cs var:stat.url ?>"><?cs var:stat.id ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.component ?></a>
-<td width="350"><?cs var:stat.name ?>
-<td width="100" align="right"><?cs var:stat.time ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Latest tickets changed</h2>
-
-<table>
-<?cs each:stat = stats.tickets.recent ?>
-<tr>
-<td width="50"><a href="<?cs var:stat.url ?>"><?cs var:stat.id ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.component ?></a>
-<td width="350"><?cs var:stat.name ?>
-<td width="100" align="right"><?cs var:stat.time ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-</div>
-
-<?cs include "footer.cs"?>
-
View
191 tracstats/templates/tickets.html
@@ -0,0 +1,191 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+
+ <head>
+ <title>Ticket Stats <py:if test="author">(${author})</py:if></title>
+ </head>
+
+<body>
+<div id="content" class="wiki">
+
+<h1>Statistics - Tickets</h1>
+
+<table>
+<py:if test="author">
+<tr><td width="150">Author</td><td align="right">${author}</td></tr>
+</py:if>
+<tr><td width="150">First ticket</td><td align="right">${mintime}</td></tr>
+<tr><td width="150">Last ticket</td><td align="right">${maxtime}</td></tr>
+<tr><td width="150">Ticket age</td><td align="right">${age}</td></tr>
+<tr><td width="150">Reporters</td><td align="right">${reporters}</td></tr>
+<tr><td width="150">Tickets</td><td align="right">${total}</td></tr>
+<tr><td width="150">Tickets-per-year</td><td align="right">${peryear}</td></tr>
+<tr><td width="150">Tickets-per-month</td><td align="right">${permonth}</td></tr>
+<tr><td width="150">Tickets-per-day</td><td align="right">${perday}</td></tr>
+<tr><td width="150">Tickets-per-hour</td><td align="right">${perhour}</td></tr>
+</table>
+
+<py:if test="history">
+<br />
+
+<h2>Open Tickets</h2>
+
+<div id="opentickets" style="width:600px;height:300px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ colors: [ "#afd8f8", "#cb4b4b" ],
+ };
+
+
+ var d1 = [<py:for each="stat in history">[${stat.x}, ${stat.opened}]<py:if
+ test="stat != history[-1]">,</py:if></py:for>];
+
+ var d2 = [<py:for each="stat in history">[${stat.x}, ${stat.assigned}]<py:if
+ test="stat != history[-1]">,</py:if></py:for>];
+
+ $.plot($("#opentickets"), [ d1, d2 ], options);
+});
+</script>
+</py:if>
+
+<br />
+
+<h2>Tickets by author</h2>
+
+<table id="ticketsbyauthor" class="tablesorter">
+<thead>
+<tr>
+ <th>Author</th>
+ <th>Reports</th>
+ <th>Changes</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in byauthor">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="100" align="right">${stat.reports}</td>
+ <td width="100" align="right">${stat.changes}</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#ticketsbyauthor").tablesorter( {sortList: [[1,1]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Tickets by component</h2>
+
+<table id="ticketsbycomponent" class="tablesorter">
+<thead>
+<tr>
+ <th>Component</th>
+ <th>Open</th>
+ <th>Total</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in bycomponent">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="100" align="right">${stat.open}</td>
+ <td width="100" align="right">${stat.total}</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#ticketsbycomponent").tablesorter( {sortList: [[1,1]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Most active tickets</h2>
+
+<table>
+<py:for each="stat in active">
+<tr>
+ <td width="50"><a href="${stat.url}">${stat.id}</a></td>
+ <td width="150"><a href="${stat.url}">${stat.component}</a></td>
+ <td width="350">${stat.name}</td>
+ <td width="75" align="right">${stat.count}</td>
+ <td width="75" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Oldest open tickets</h2>
+
+<table>
+<py:for each="stat in oldest">
+<tr>
+ <td width="50"><a href="${stat.url}">${stat.id}</a></td>
+ <td width="150"><a href="${stat.url2}">${stat.component}</a></td>
+ <td width="350">${stat.name}</td>
+ <td width="100" align="right">${stat.time}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Latest tickets reported</h2>
+
+<table>
+<py:for each="stat in newest">
+<tr>
+ <td width="50"><a href="${stat.url}">${stat.id}</a></td>
+ <td width="150"><a href="${stat.url2}">${stat.component}</a></td>
+ <td width="350">${stat.name}</td>
+ <td width="100" align="right">${stat.time}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Latest tickets changed</h2>
+
+<table>
+<py:for each="stat in recent">
+<tr>
+ <td width="50"><a href="${stat.url}">${stat.id}</a></td>
+ <td width="150"><a href="${stat.url2}">${stat.component}</a></td>
+ <td width="350">${stat.name}</td>
+ <td width="100" align="right">${stat.time}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+</div>
+
+</body>
+</html>
+
View
131 tracstats/templates/wiki.cs
@@ -1,131 +0,0 @@
-<?cs include "header.cs"?>
-<?cs include "macros.cs"?>
-
-<?cs include "nav.cs"?>
-
-<div id="content" class="wiki">
-
-<h1>Statistics - Wiki</h1>
-
-<table>
-<?cs if:stats.author ?>
-<tr><td width="150">Author<td align="right"><?cs var:stats.author ?></tr>
-<?cs /if ?>
-<tr><td width="150">First edit<td align="right"><?cs var:stats.wiki.mintime ?></tr>
-<tr><td width="150">Last edit<td align="right"><?cs var:stats.wiki.maxtime ?></tr>
-<tr><td width="150">Wiki age<td align="right"><?cs var:stats.wiki.age ?></tr>
-<tr><td width="150">Editors<td align="right"><?cs var:stats.wiki.editors ?></tr>
-<tr><td width="150">Edits<td align="right"><?cs var:stats.wiki.edits ?></tr>
-<tr><td width="150">Edits-per-year<td align="right"><?cs var:stats.wiki.peryear ?></tr>
-<tr><td width="150">Edits-per-month<td align="right"><?cs var:stats.wiki.permonth ?></tr>
-<tr><td width="150">Edits-per-day<td align="right"><?cs var:stats.wiki.perday ?></tr>
-<tr><td width="150">Edits-per-hour<td align="right"><?cs var:stats.wiki.perhour ?></tr>
-</table>
-
-<?cs if:len(stats.wiki.history) > 0 ?>
-<br>
-
-<h2>Total Pages</h2>
-
-<div id="totalpages" style="width:600px;height:300px;"></div>
-
-<script language="javascript" type="text/javascript">
-$(function () {
-
- var options = {
- lines: { show: true, fill: true },
- xaxis: { mode: "time", timeformat: "%b %y" },
- colors: [ "#afd8f8" ],
- };
-
- var d = [<?cs
- each:stat = stats.wiki.history ?><?cs
- set:last = name(stat) == len(stats.wiki.history) - #1 ?>[<?cs
- var:stat.x ?>, <?cs
- var:stat.y ?>]<?cs if:!last ?>,<?cs /if ?><?cs /each ?>];
-
- $.plot($("#totalpages"), [ d ], options);
-});
-</script>
-<?cs /if ?>
-
-<br>
-
-<h2>Edits by author</h2>
-
-<table id="editsbyauthor" class="tablesorter">
-<thead>
-<tr>
- <th>Author
- <th>Edits
- <th>Pages
- <th>Percent
-</tr>
-</thead>
-<tbody>
-<?cs each:stat = stats.wiki.byauthor ?>
-<tr>
-<td width="150"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="100" align="right"><?cs var:stat.count ?>
-<td width="100" align="right"><?cs var:stat.pages ?>
-<td width="100" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</tbody>
-</table>
-
-<script language="javascript" type="text/javascript">
-$(document).ready(function()
- {
- $("#editsbyauthor").tablesorter( {sortList: [[1,1]]} );
- }
-);
-</script>
-
-<br>
-
-<h2>Latest wiki pages changed</h2>
-
-<table>
-<?cs each:stat = stats.wiki.recent ?>
-<tr>
-<td width="200"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="150"><a href="<?cs var:stat.url2 ?>"><?cs var:stat.author ?></a>
-<td width="100" align="right"><?cs var:stat.time ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Most active wiki pages</h2>
-
-<table>
-<?cs each:stat = stats.wiki.pages ?>
-<tr>
-<td width="200"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="75" align="right"><?cs var:stat.count ?>
-<td width="75" align="right"><?cs var:stat.percent ?>%
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-<h2>Largest wiki pages</h2>
-
-<table>
-<?cs each:stat = stats.wiki.largest ?>
-<tr>
-<td width="200"><a href="<?cs var:stat.url ?>"><?cs var:stat.name ?></a>
-<td width="150" align="right"><?cs var:stat.size ?>
-</tr>
-<?cs /each ?>
-</table>
-
-<br>
-
-</div>
-
-<?cs include "footer.cs"?>
-
View
137 tracstats/templates/wiki.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="layout.html" />
+
+ <head>
+ <title>Wiki Stats <py:if test="author">(${author})</py:if></title>
+ </head>
+
+<body>
+<div id="content" class="wiki">
+
+<h1>Statistics - Wiki</h1>
+
+<table>
+<py:if test="author">
+<tr><td width="150">Author</td><td align="right">${author}</td></tr>
+</py:if>
+<tr><td width="150">First edit</td><td align="right">${mintime}</td></tr>
+<tr><td width="150">Last edit</td><td align="right">${maxtime}</td></tr>
+<tr><td width="150">Wiki age</td><td align="right">${age}</td></tr>
+<tr><td width="150">Editors</td><td align="right">${editors}</td></tr>
+<tr><td width="150">Edits</td><td align="right">${edits}</td></tr>
+<tr><td width="150">Edits-per-year</td><td align="right">${peryear}</td></tr>
+<tr><td width="150">Edits-per-month</td><td align="right">${permonth}</td></tr>
+<tr><td width="150">Edits-per-day</td><td align="right">${perday}</td></tr>
+<tr><td width="150">Edits-per-hour</td><td align="right">${perhour}</td></tr>
+</table>
+
+<py:if test="history">
+<br />
+
+<h2>Total Pages</h2>
+
+<div id="totalpages" style="width:600px;height:300px;"></div>
+
+<script language="javascript" type="text/javascript">
+$(function () {
+
+ var options = {
+ lines: { show: true, fill: true },
+ xaxis: { mode: "time", timeformat: "%b %y" },
+ colors: [ "#afd8f8" ],
+ };
+
+ var d = [<py:for each="stat in history">[${stat.x}, ${stat.y}]<py:if
+ test="stat != history[-1]">,</py:if></py:for>];
+
+ $.plot($("#totalpages"), [ d ], options);
+});
+</script>
+</py:if>
+
+<br />
+
+<h2>Edits by author</h2>
+
+<table id="editsbyauthor" class="tablesorter">
+<thead>
+<tr>
+ <th>Author</th>
+ <th>Edits</th>
+ <th>Pages</th>
+ <th>Percent</th>
+</tr>
+</thead>
+<tbody>
+<py:for each="stat in byauthor">
+<tr>
+ <td width="150"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="100" align="right">${stat.count}</td>
+ <td width="100" align="right">${stat.pages}</td>
+ <td width="100" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</tbody>
+</table>
+
+<script language="javascript" type="text/javascript">
+$(document).ready(function()
+ {
+ $("#editsbyauthor").tablesorter( {sortList: [[1,1]]} );
+ }
+);
+</script>
+
+<br />
+
+<h2>Latest wiki pages changed</h2>
+
+<table>
+<py:for each="stat in recent">
+<tr>
+ <td width="200"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="150"><a href="${stat.url2}">${stat.author}</a></td>
+ <td width="100" align="right">${stat.time}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Most active wiki pages</h2>
+
+<table>
+<py:for each="stat in pages">
+<tr>
+ <td width="200"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="75" align="right">${stat.count}</td>
+ <td width="75" align="right">${stat.percent}%</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+<h2>Largest wiki pages</h2>
+
+<table>
+<py:for each="stat in largest">
+<tr>
+ <td width="200"><a href="${stat.url}">${stat.name}</a></td>
+ <td width="150" align="right">${stat.size}</td>
+</tr>
+</py:for>
+</table>
+
+<br />
+
+</div>
+
+</body>
+</html>
View
239 tracstats/web_ui.py
@@ -16,17 +16,17 @@
from trac.util.html import html, Markup
from trac.web import IRequestHandler
from trac.web.chrome import INavigationContributor, ITemplateProvider
-from trac.web.chrome import add_stylesheet, add_script
+from trac.web.chrome import add_ctxtnav, add_stylesheet, add_script
class TracStatsPlugin(Component):
implements(INavigationContributor, IPermissionRequestor, IRequestHandler, ITemplateProvider)
-
+
# IPermissionRequestor methods
-
+
def get_permission_actions(self):
return ['STATS_VIEW']
-
+
# INavigationContributor methods
def get_active_navigation_item(self, req):
@@ -42,11 +42,11 @@ def get_navigation_items(self, req):
def get_htdocs_dirs(self):
from pkg_resources import resource_filename
return [('stats', resource_filename(__name__, 'htdocs'))]
-
+
def get_templates_dirs(self):
from pkg_resources import resource_filename
return [resource_filename(__name__, 'templates')]
-
+
# IRequestHandler methods
def match_request(self, req):
@@ -71,7 +71,8 @@ def process_request(self, req):
else:
where = ''
- req.hdf['stats.author'] = author
+ data = {}
+ data['author'] = author
db = self.env.get_db_cnx()
cursor = db.cursor()
@@ -89,27 +90,33 @@ def process_request(self, req):
add_script(req, 'stats/jquery.sparkline.min.js')
add_script(req, 'stats/excanvas.pack.js')
+ # Include context navigation links
+ add_ctxtnav(req, 'Summary', req.href.stats())
+ add_ctxtnav(req, 'Code', req.href.stats('code'))
+ add_ctxtnav(req, 'Wiki', req.href.stats('wiki'))
+ add_ctxtnav(req, 'Tickets', req.href.stats('tickets'))
+
if path == '/':
- req.hdf['title'] = 'Stats'
- return self._process(req, cursor, where)
-
+ data['title'] = 'Stats'
+ return self._process(req, cursor, where, data)
+
elif path == '/code':
- req.hdf['title'] = 'Code' + (author and (' (%s)' % author))
- return self._process_code(req, cursor, where)
+ data['title'] = 'Code' + (author and (' (%s)' % author))
+ return self._process_code(req, cursor, where, data)
elif path == '/wiki':
- req.hdf['title'] = 'Wiki ' + (author and (' (%s)' % author))
- return self._process_wiki(req, cursor, where)
+ data['title'] = 'Wiki ' + (author and (' (%s)' % author))
+ return self._process_wiki(req, cursor, where, data)
elif path == '/tickets':
- req.hdf['title'] = 'Tickets' + (author and (' (%s)' % author))
- return self._process_tickets(req, cursor, where)
+ data['title'] = 'Tickets' + (author and (' (%s)' % author))
+ return self._process_tickets(req, cursor, where, data)
else:
raise ValueError, "unknown path '%s'" % path
- def _process(self, req, cursor, where):
+ def _process(self, req, cursor, where, data):
cursor.execute("""
select count(distinct author),
@@ -124,10 +131,10 @@ def _process(self, req, cursor, where):
cursor.execute("select count(distinct id) from ticket")
tickets, = cursor.fetchall()[0]
- req.hdf['stats.authors'] = authors
- req.hdf['stats.revisions'] = revisions
- req.hdf['stats.pages'] = pages
- req.hdf['stats.tickets'] = tickets
+ data['authors'] = authors
+ data['revisions'] = revisions
+ data['pages'] = pages
+ data['tickets'] = tickets
cursor.execute("select min(time), max(time) from revision")
mintime, maxtime = cursor.fetchall()[0]
@@ -140,9 +147,9 @@ def _process(self, req, cursor, where):
years = td.days // 365
days = (td.days % 365)
hours = td.seconds // 3600
- req.hdf['stats.years'] = years
- req.hdf['stats.days'] = days
- req.hdf['stats.hours'] = hours
+ data['years'] = years
+ data['days'] = days
+ data['hours'] = hours
now = time.time()
start = now - (52 * 7 * 24 * 60 * 60)
@@ -167,8 +174,8 @@ def _process(self, req, cursor, where):
if week < 0:
year -= 1
week = 52
- req.hdf['stats.code.weeks'] = list(reversed(stats))
-
+ data['weeks'] = list(reversed(stats))
+
now = time.time()
start = now - (30 * 24 * 60 * 60)
cursor.execute("""
@@ -185,7 +192,7 @@ def _process(self, req, cursor, where):
for author, commits in rows:
stats.append({'name': author,
'url': req.href.stats("code", author=author),})
- req.hdf['stats.code.byauthors'] = stats
+ data['byauthors'] = stats
cursor.execute("""
select path
@@ -208,7 +215,7 @@ def _process(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(1), reverse=True)[:10]:
stats.append({'name': k,
'url': req.href.log(k),})
- req.hdf['stats.code.bypaths'] = stats
+ data['bypaths'] = stats
d = {}
for path, in rows:
@@ -225,11 +232,11 @@ def _process(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(1), reverse=True)[:10]:
stats.append({'name': k,
'url': req.href.log(k),})
- req.hdf['stats.code.byproject'] = stats
+ data['byproject'] = stats
- return 'stats.cs', None
+ return 'stats.html', data, None
- def _process_code(self, req, cursor, where):
+ def _process_code(self, req, cursor, where, data):
project = req.args.get('project', '')
@@ -256,7 +263,7 @@ def _process_code(self, req, cursor, where):
select rev
from revision
""" + where)
-
+
cursor.execute("""
select min(cast(rev as int)),
max(cast(rev as int)),
@@ -269,16 +276,16 @@ def _process_code(self, req, cursor, where):
""")
minrev, maxrev, mintime, maxtime, commits, developers = cursor.fetchall()[0]
- req.hdf['stats.code.maxrev'] = maxrev
- req.hdf['stats.code.minrev'] = minrev
+ data['maxrev'] = maxrev
+ data['minrev'] = minrev
if maxtime:
- req.hdf['stats.code.maxtime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(maxtime))
+ data['maxtime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(maxtime))
else:
- req.hdf['stats.code.maxtime'] = 'N/A'
+ data['maxtime'] = 'N/A'
if mintime:
- req.hdf['stats.code.mintime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(mintime))
+ data['mintime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(mintime))
else:
- req.hdf['stats.code.mintime'] = 'N/A'
+ data['mintime'] = 'N/A'
if mintime and maxtime:
age = maxtime - mintime
@@ -288,20 +295,20 @@ def _process_code(self, req, cursor, where):
years = td.days // 365
days = (td.days % 365)
hours = td.seconds // 3600
- req.hdf['stats.code.age'] = '%d years, %d days, %d hours' % (years, days, hours)
+ data['age'] = '%d years, %d days, %d hours' % (years, days, hours)
- req.hdf['stats.code.developers'] = developers
- req.hdf['stats.code.commits'] = commits
+ data['developers'] = developers
+ data['commits'] = commits
if age:
- req.hdf['stats.code.commitsperyear'] = '%.2f' % (commits * 365 * 24 * 60 * 60. / age)
- req.hdf['stats.code.commitspermonth'] = '%.2f' % (commits * 30 * 24 * 60 * 60. / age)
- req.hdf['stats.code.commitsperday'] = '%.2f' % (commits * 24 * 60 * 60. / age)
- req.hdf['stats.code.commitsperhour'] = '%.2f' % (commits * 60 * 60. / age)
+ data['commitsperyear'] = '%.2f' % (commits * 365 * 24 * 60 * 60. / age)
+ data['commitspermonth'] = '%.2f' % (commits * 30 * 24 * 60 * 60. / age)
+ data['commitsperday'] = '%.2f' % (commits * 24 * 60 * 60. / age)
+ data['commitsperhour'] = '%.2f' % (commits * 60 * 60. / age)
else:
- req.hdf['stats.code.commitsperyear'] = 0
- req.hdf['stats.code.commitspermonth'] = 0
- req.hdf['stats.code.commitsperday'] = 0
- req.hdf['stats.code.commitsperhour'] = 0
+ data['commitsperyear'] = 0
+ data['commitspermonth'] = 0
+ data['commitsperday'] = 0
+ data['commitsperhour'] = 0
cursor.execute("""
select rev, time, author, length(message)
@@ -332,11 +339,11 @@ def _process_code(self, req, cursor, where):
if revisions:
avgsize = sum(int(msg) for _, _, _, msg in revisions) / float(len(revisions))
avgchanges = float(len(changes)) / len(revisions)
- req.hdf['stats.code.logentry'] = '%d chars' % avgsize
- req.hdf['stats.code.changes'] = '%.2f' % avgchanges
+ data['logentry'] = '%d chars' % avgsize
+ data['changes'] = '%.2f' % avgchanges
else:
- req.hdf['stats.code.logentry'] = 'N/A'
- req.hdf['stats.code.changes'] = 'N/A'
+ data['logentry'] = 'N/A'
+ data['changes'] = 'N/A'
cursor.execute("""
select r.author,
@@ -395,7 +402,7 @@ def _process_code(self, req, cursor, where):
'changes': change,
'paths': paths,
'weeks': list(reversed(weeks)),})
- req.hdf['stats.code.byauthors'] = stats
+ data['byauthors'] = stats
cursor.execute("""
select r.rev, r.time, r.author, r.message
@@ -412,7 +419,7 @@ def _process_code(self, req, cursor, where):
'url': req.href.changeset(rev),
'url2': req.href.stats("code", author=author),
'time': pretty_timedelta(to_datetime(t)),})
- req.hdf['stats.code.recent'] = stats
+ data['recent'] = stats
times = dict((rev, t) for rev, t, _, _ in revisions)
@@ -431,7 +438,7 @@ def _process_code(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(0))[::steps]:
stats.append({'x': k,
'y': v,})
- req.hdf['stats.code.totalfiles'] = stats
+ data['totalfiles'] = stats
d = {}
total = 0
@@ -443,7 +450,7 @@ def _process_code(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(0))[::steps]:
stats.append({'x': k,
'y': v,})
- req.hdf['stats.code.totalcommits'] = stats
+ data['totalcommits'] = stats
times = dict((rev, t) for rev, t, _, _ in revisions)
d = {}
@@ -456,7 +463,7 @@ def _process_code(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(0))[::steps]:
stats.append({'x': k,
'y': v,})
- req.hdf['stats.code.totalchanges'] = stats
+ data['totalchanges'] = stats
d = {}
for rev, path, change_type, _ in changes:
@@ -471,7 +478,7 @@ def _process_code(self, req, cursor, where):
'url': req.href.log(k),
'count': v,
'percent': '%.2f' % (100 * v / total)})
- req.hdf['stats.code.byfiles'] = stats
+ data['byfiles'] = stats
d = {}
for rev, path, change_type, author in changes:
@@ -496,7 +503,7 @@ def _process_code(self, req, cursor, where):
'deletes': deletes,
'edits': edits,
'moves': moves})
- req.hdf['stats.code.bychangetypes'] = stats
+ data['bychangetypes'] = stats
d = {}
for rev, path, change_type, _ in changes:
@@ -514,7 +521,7 @@ def _process_code(self, req, cursor, where):
'url': req.href.log(k),
'count': v,
'percent': '%.2f' % (100 * v / total)})
- req.hdf['stats.code.bypaths'] = stats
+ data['bypaths'] = stats
d = {}
for rev, path, change_type, _ in changes:
@@ -534,7 +541,7 @@ def _process_code(self, req, cursor, where):
stats.append({'name': k,
'count': v,
'percent': '%.2f' % (100 * v / total)})
- req.hdf['stats.code.byfiletypes'] = stats
+ data['byfiletypes'] = stats
d = {}
for rev, path, change_type, _ in changes:
@@ -555,7 +562,7 @@ def _process_code(self, req, cursor, where):
'changes': v[0],
'commits': len(v[1]),
'paths': len(v[2]),})
- req.hdf['stats.code.byproject'] = stats
+ data['byproject'] = stats
hours = ['0%d:00' % i for i in range(10)]
hours += ['%d:00' % i for i in range(10, 24)]
@@ -568,7 +575,7 @@ def _process_code(self, req, cursor, where):
for x, y in sorted(d.iteritems()):
stats.append({'x': x,
'y': y,})
- req.hdf['stats.code.byhour'] = stats
+ data['byhour'] = stats
days = dict((day, i) for i, day in enumerate(('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')))
d = dict((i, 0) for i in range(7))
@@ -579,7 +586,7 @@ def _process_code(self, req, cursor, where):
for x, y in sorted(d.iteritems()):
stats.append({'x': x,
'y': y,})
- req.hdf['stats.code.byday'] = stats
+ data['byday'] = stats
d = {}
for _, t, _, _ in revisions:
@@ -603,7 +610,7 @@ def _process_code(self, req, cursor, where):
for k, v in sorted(d.iteritems()):
stats.append({'x': int(k * 1000),
'y': v})
- req.hdf['stats.code.bymonth'] = stats
+ data['bymonth'] = stats
cursor.execute("select distinct(author) from revision")
authors = set(s for s, in cursor.fetchall())
@@ -645,25 +652,25 @@ def _process_code(self, req, cursor, where):
index = min(index, len(fonts) - 1)
stats.append({'word': k,
'size': fonts[index]})
- req.hdf['stats.code.cloud'] = stats
+ data['cloud'] = stats
- return 'code.cs', None
+ return 'code.html', data, None
- def _process_wiki(self, req, cursor, where):
+ def _process_wiki(self, req, cursor, where, data):
cursor.execute("select min(time), max(time), count(*), count(distinct author) from wiki " + where)
mintime, maxtime, edits, editors = cursor.fetchall()[0]
- req.hdf['stats.wiki.editors'] = editors
+ data['editors'] = editors
if maxtime:
- req.hdf['stats.wiki.maxtime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(maxtime))
+ data['maxtime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(maxtime))
else:
- req.hdf['stats.wiki.maxtime'] = 'N/A'
+ data['maxtime'] = 'N/A'
if mintime:
- req.hdf['stats.wiki.mintime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(mintime))
+ data['mintime'] = time.strftime('%a %m/%d/%Y %H:%M:%S %Z', time.localtime(mintime))
else:
- req.hdf['stats.wiki.mintime'] = 'N/A'
+ data['mintime'] = 'N/A'
if mintime and maxtime:
age = maxtime - mintime
@@ -673,19 +680,19 @@ def _process_wiki(self, req, cursor, where):
years = td.days // 365
days = (td.days % 365)
hours = td.seconds // 3600
- req.hdf['stats.wiki.age'] = '%d years, %d days, %d hours' % (years, days, hours)
+ data['age'] = '%d years, %d days, %d hours' % (years, days, hours)
- req.hdf['stats.wiki.edits'] = edits
+ data['edits'] = edits
if age:
- req.hdf['stats.wiki.peryear'] = '%.2f' % (edits * 365 * 24 * 60 * 60. / age)
- req.hdf['stats.wiki.permonth'] = '%.2f' % (edits * 30 * 24 * 60 * 60. / age)
- req.hdf['stats.wiki.perday'] = '%.2f' % (edits * 24 * 60 * 60. / age)
- req.hdf['stats.wiki.perhour'] = '%.2f' % (edits * 60 * 60. / age)
+ data['peryear'] = '%.2f' % (edits * 365 * 24 * 60 * 60. / age)
+ data['permonth'] = '%.2f' % (edits * 30 * 24 * 60 * 60. / age)
+ data['perday'] = '%.2f' % (edits * 24 * 60 * 60. / age)
+ data['perhour'] = '%.2f' % (edits * 60 * 60. / age)
else:
- req.hdf['stats.wiki.peryear'] = 0
- req.hdf['stats.wiki.permonth'] = 0
- req.hdf['stats.wiki.perday'] = 0
- req.hdf['stats.wiki.perhour'] = 0
+ data['peryear'] = 0
+ data['permonth'] = 0
+ data['perday'] = 0
+ data['perhour'] = 0
cursor.execute("select name, author, count(*) from wiki " + where + " group by 1, 2")
pages = cursor.fetchall()
@@ -705,7 +712,7 @@ def _process_wiki(self, req, cursor, where):
'count': v[0],
'pages': len(v[1]),
'percent': '%.2f' % (100 * v[0] / total)})
- req.hdf['stats.wiki.byauthor'] = stats
+ data['byauthor'] = stats
cursor.execute("select name, time from wiki " + where + " order by 2 asc")
history = cursor.fetchall()
@@ -722,7 +729,7 @@ def _process_wiki(self, req, cursor, where):
for k, v in sorted(d.iteritems(), key=itemgetter(0))[::steps]:
stats.append({'x': k,
'y': v,})
- req.hdf['stats.wiki.history'] = stats
+ data['history'] = stats
d = {}
for name, _, count in pages:
@@ -737,7 +744,7 @@ def _process_wiki(self, req, cursor, where):
'url': req.href.wiki(k),
'count': v,
'percent': '%.2f' % (100 * v / total)})
- req.hdf['stats.wiki.pages'] = stats
+ data['pages'] = stats
cursor.execute("select name, length(text) from wiki " + where + " group by 1 having version = max(version) order by 2 desc limit 10")
rows = cursor.fetchall()
@@ -747,37 +754,37 @@ def _process_wiki(self, req, cursor, where):
stats.append({'name': k,
'url': req.href.wiki(k),
'size': v})
- req.hdf['stats.wiki.largest'] = stats
+ data['l