diff --git a/src/IDF/Views/Issue.php b/src/IDF/Views/Issue.php index 91fdc40..33f768c 100644 --- a/src/IDF/Views/Issue.php +++ b/src/IDF/Views/Issue.php @@ -78,6 +78,68 @@ class IDF_Views_Issue } /** + * View the issue summary. + * TODO Add thoses data in cache, and process it only after an issue update + */ + public $summary_precond = array('IDF_Precondition::accessIssues'); + public function summary($request, $match) + { + $prj = $request->project; + $opened = $prj->getIssueCountByStatus('open'); + $closed = $prj->getIssueCountByStatus('closed'); + $otags = implode(',', $prj->getTagIdsByStatus('open')); + + // Issue status statistics + $status = array(); + $status['Open'] = array($opened, (int)(100 * $opened / ($opened + $closed))); + $status['Closed'] = array($closed, (int)(100 * $closed / ($opened + $closed))); + + // Issue owner statistics + $sqlIssueTable = Pluf::factory('IDF_Issue')->getSqlTable(); + $sqlUsersTable = Pluf::factory('Pluf_User')->getSqlTable(); + $query = <<<"QUERY" +SELECT CONCAT(first_name, " ", last_name) as name, nb FROM (SELECT uid as id,count(uid) as nb FROM (SELECT ifnull(owner, -1) as uid FROM $sqlIssueTable WHERE status IN ($otags)) as ff group by uid) AS ff LEFT JOIN $sqlUsersTable using(id) +QUERY; + $db = Pluf::db(); + $dbData = $db->select($query); + $ownerStatistics = array(); + foreach ($dbData as $k => $v) { + $key = ($v['name'] === null) ? __('Not assigned') : $v['name']; + $ownerStatistics[$key] = array($v['nb'], (int)(100 * $v['nb'] / $opened)); + } + + // Issue class tag statistics + $tags = $prj->getTagCloud(); + $tagStatistics = array(); + foreach ($tags as $t) { + $tagStatistics[$t->class][$t->name] = array($t->nb_use, $t->id); + } + foreach($tagStatistics as $k => $v) { + $nbIssueInClass = 0; + foreach ($v as $val) { + $nbIssueInClass += $val[0]; + } + foreach ($v as $kk => $vv) { + $tagStatistics[$k][$kk] = array($vv[0], (int)(100 * $vv[0] / $nbIssueInClass), $vv[1]); + } + } + + // Sort + krsort($tagStatistics); + arsort($ownerStatistics); + + $title = sprintf(__('Summary of tracked issues in %s.'), (string) $prj); + return Pluf_Shortcuts_RenderToResponse('idf/issues/summary.html', + array('page_title' => $title, + 'project' => $prj, + 'tagStatistics' => $tagStatistics, + 'ownerStatistics' => $ownerStatistics, + 'status' => $status, + ), + $request); + } + + /** * View the issues watch list of a given user. * Limited to a specified project */ diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php index 55c47fa..03779c0 100644 --- a/src/IDF/conf/urls.php +++ b/src/IDF/conf/urls.php @@ -117,6 +117,11 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#', 'base' => $base, 'model' => 'IDF_Views_Issue', 'method' => 'index'); + +$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#', + 'base' => $base, + 'model' => 'IDF_Views_Issue', + 'method' => 'summary'); $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#', 'base' => $base, diff --git a/src/IDF/templates/idf/issues/base.html b/src/IDF/templates/idf/issues/base.html index 779de34..636d5da 100644 --- a/src/IDF/templates/idf/issues/base.html +++ b/src/IDF/templates/idf/issues/base.html @@ -2,7 +2,8 @@ {block tabissues} class="active"{/block} {block subtabs}
-{trans 'Open Issues'} +{trans 'Summary'} +| {trans 'Open Issues'} {if !$user.isAnonymous()} | {trans 'New Issue'} | {trans 'My Issues'} | {trans 'My watch list'}{/if} |
diff --git a/src/IDF/templates/idf/issues/summary.html b/src/IDF/templates/idf/issues/summary.html new file mode 100644 index 0000000..14765e5 --- /dev/null +++ b/src/IDF/templates/idf/issues/summary.html @@ -0,0 +1,89 @@ +{extends "idf/issues/base.html"} + +{block docclass}yui-t2{assign $inSummaryIssues=true}{/block} + +{block body} +
+{foreach $tagStatistics as $key => $class} +
+

Unresolved: By {$key}

+ + +{foreach $class as $key => $value} + + + + + +{/foreach} + +
{$key}{$value[0]} + + + + + + +
+
+
   {$value[1]}%
+
+
+{/foreach} +
+ +
+ +
+

Status Summary

+ + +{foreach $status as $key => $value} + + + + + +{/foreach} + +
{$key}{$value[0]} + + + + + + +
+
+
   {$value[1]}%
+
+
+ +
+

Unresolved: By Assignee

+ + +{foreach $ownerStatistics as $key => $value} + + + + + +{/foreach} + +
{$key}{$value[0]} + + + + + + +
+
+
   {$value[1]}%
+
+
+ +
+ +{/block} diff --git a/www/media/idf/css/style.css b/www/media/idf/css/style.css index 3480828..be16143 100644 --- a/www/media/idf/css/style.css +++ b/www/media/idf/css/style.css @@ -1104,3 +1104,49 @@ div.p-list-private { right: -3px; position: relative; } + +/* + * Issue summary + */ +div.issue-summary { + float: left; + width: 50%; +} + +div.issue-summary > div { + margin-right: 3em; + padding-top: 1em; +} + +div.issue-summary h2 { + border-bottom: 1px solid #A5E26A; +} + +table.issue-summary { + width: 100%; +} + +table.issue-summary tr td { + border: 0; + padding: .1em; +} + +table.issue-summary td.graph { + width: 60%; +} + +table.issue-summary td.count { + text-align: right; + padding-right: .5em; +} + +table.graph { + width: 100%; + margin: 0; + padding: 0; +} + +td.graph-color { + background: #3C78B5; +} +