From 6e305eb5418a8690b9b6f5de2a0b457954376a88 Mon Sep 17 00:00:00 2001
From: Thomas Keller
Date: Sat, 24 Dec 2011 02:45:01 +0100
Subject: [PATCH] Add filtering and sorting capabilities to the project list
page and also render the project activity with a small bar graph below the
logo image. Sanitize the tagcloud css.
---
src/IDF/Forge.php | 19 ++++++++
src/IDF/Project.php | 10 +++--
src/IDF/Tag.php | 12 +++++
src/IDF/Views.php | 45 ++++++++++++++-----
src/IDF/conf/urls.php | 2 +-
src/IDF/templates/idf/issues/search.html | 4 +-
src/IDF/templates/idf/listProjects.html | 56 ++++++++++++++++++------
src/IDF/templates/idf/tags-cloud.html | 4 +-
www/media/idf/css/style.css | 28 +++++++++---
9 files changed, 138 insertions(+), 42 deletions(-)
diff --git a/src/IDF/Forge.php b/src/IDF/Forge.php
index 97ce9c1..fc4d430 100644
--- a/src/IDF/Forge.php
+++ b/src/IDF/Forge.php
@@ -51,4 +51,23 @@ class IDF_Forge
public function setProjectLabels($labels) {
$this->conf->setVal('project_labels', $labels);
}
+
+ public function getProjectLabelsWithCounts() {
+ $sql = new Pluf_SQL('project=0');
+ $tagList = Pluf::factory('IDF_Tag')->getList(array(
+ 'filter' => $sql->gen(),
+ 'view' => 'join_projects',
+ 'order' => 'class ASC, lcname ASC'
+ ));
+
+ $tags = array();
+ foreach ($tagList as $tag) {
+ // group by class
+ if (!array_key_exists($tag->class, $tags)) {
+ $tags[$tag->class] = array();
+ }
+ $tags[$tag->class][] = $tag;
+ }
+ return $tags;
+ }
}
\ No newline at end of file
diff --git a/src/IDF/Project.php b/src/IDF/Project.php
index fc8a340..8cafd2c 100644
--- a/src/IDF/Project.php
+++ b/src/IDF/Project.php
@@ -108,13 +108,15 @@ class IDF_Project extends Pluf_Model
'verbose' => __('current project activity'),
),
);
- $table = $this->_con->pfx.'idf_projectactivities';
+ $activityTable = $this->_con->pfx.'idf_projectactivities';
+ $tagTable = $this->_con->pfx.'idf_project_idf_tag_assoc';
$this->_a['views'] = array(
- 'join_activities' =>
+ 'join_activities_and_tags' =>
array(
- 'join' => 'LEFT JOIN '.$table
- .' ON current_activity='.$table.'.id',
+ 'join' => 'LEFT JOIN '.$activityTable.' ON current_activity='.$activityTable.'.id '
+ .'LEFT JOIN '.$tagTable.' ON idf_project_id='.$this->getSqlTable().'.id',
'select' => $this->getSelect().', date, value',
+ 'group' => $this->getSqlTable().'.id',
'props' => array(
'date' => 'current_activity_date',
'value' => 'current_activity_value'
diff --git a/src/IDF/Tag.php b/src/IDF/Tag.php
index 24441a6..b9fa25d 100644
--- a/src/IDF/Tag.php
+++ b/src/IDF/Tag.php
@@ -75,6 +75,18 @@ class IDF_Tag extends Pluf_Model
),
);
+ $table = $this->_con->pfx.'idf_project_idf_tag_assoc';
+ $this->_a['views'] = array(
+ 'join_projects' =>
+ array(
+ 'join' => 'LEFT JOIN '.$table
+ .' ON idf_tag_id=id',
+ 'select' => $this->getSelect().',COUNT(idf_project_id) as project_count',
+ 'group' => 'idf_tag_id',
+ 'props' => array('project_count' => 'project_count'),
+ ),
+ );
+
$this->_a['idx'] = array(
'lcname_idx' =>
array(
diff --git a/src/IDF/Views.php b/src/IDF/Views.php
index bd1569f..3eaa01c 100644
--- a/src/IDF/Views.php
+++ b/src/IDF/Views.php
@@ -38,6 +38,7 @@ class IDF_Views
{
// TODO: add a switch here later on to determine whether the project list
// or a custom start page should be displayed
+ $match = array('', 'all', 'name');
return $this->listProjects($request, $match);
}
@@ -47,15 +48,30 @@ class IDF_Views
* Only the public projects are listed or the private with correct
* rights.
*/
- public function listProjects($request, $match, $api=false)
+ public function listProjects($request, $match)
{
- $projects = self::getProjects($request->user);
- $stats = self::getProjectsStatistics($projects);
+ list(, $tagId, $order) = $match;
+
+ $tag = false;
+ if ($tagId !== 'all') {
+ $tag = Pluf::factory('IDF_Tag')->get($match[1]);
+ // ignore non-global tags
+ if ($tag !== false && $tag->project > 0) {
+ $tag = false;
+ }
+ }
+ $order = in_array($order, array('name', 'activity')) ? $order : 'name';
+
+ $projects = self::getProjects($request->user, $tag, $order);
+ $stats = self::getProjectsStatistics($projects);
+ $projectLabels = IDF_Forge::instance()->getProjectLabelsWithCounts();
- if ($api == true) return $projects;
return Pluf_Shortcuts_RenderToResponse('idf/listProjects.html',
array('page_title' => __('Projects'),
'projects' => $projects,
+ 'projectLabels' => $projectLabels,
+ 'tag' => $tag,
+ 'order' => $order,
'stats' => new Pluf_Template_ContextVars($stats)),
$request);
}
@@ -335,16 +351,20 @@ class IDF_Views
}
/**
- * Returns a list of projects accessible for the user.
+ * Returns a list of projects accessible for the user and optionally filtered by tag.
*
* @param Pluf_User
+ * @param IDF_Tag
* @return ArrayObject IDF_Project
*/
- public static function getProjects($user)
+ public static function getProjects($user, $tag = false, $order = 'name')
{
$db =& Pluf::db();
$false = Pluf_DB_BooleanToDb(false, $db);
$sql = new Pluf_SQL(1);
+ if ($tag !== false) {
+ $sql->SAnd(new Pluf_SQL('idf_tag_id=%s', $tag->id));
+ }
if ($user->isAnonymous())
{
@@ -373,10 +393,14 @@ class IDF_Views
$sql->SAnd($authSql);
}
+ $orderTypes = array(
+ 'name' => 'name ASC',
+ 'activity' => 'value DESC, name ASC',
+ );
return Pluf::factory('IDF_Project')->getList(array(
'filter'=> $sql->gen(),
- 'view' => 'join_activities',
- 'order' => 'name ASC'
+ 'view' => 'join_activities_and_tags',
+ 'order' => $orderTypes[$order],
));
}
@@ -397,7 +421,7 @@ class IDF_Views
// Count for each projects
foreach ($projects as $p) {
- $pstats = $p->getStats ();
+ $pstats = $p->getStats();
$forgestats['downloads'] += $pstats['downloads'];
$forgestats['reviews'] += $pstats['reviews'];
$forgestats['issues'] += $pstats['issues'];
@@ -405,9 +429,6 @@ class IDF_Views
$forgestats['commits'] += $pstats['commits'];
}
- // Count projects
- $forgestats['projects'] = count($projects);
-
// Count members
$sql = new Pluf_SQL('first_name != %s', array('---'));
$forgestats['members'] = Pluf::factory('Pluf_User')
diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php
index 1755ae6..5995e5b 100644
--- a/src/IDF/conf/urls.php
+++ b/src/IDF/conf/urls.php
@@ -29,7 +29,7 @@ $ctl[] = array('regex' => '#^/$#',
'model' => 'IDF_Views',
'method' => 'index');
-$ctl[] = array('regex' => '#^/label/(\d+)/$#',
+$ctl[] = array('regex' => '#^/label/(\w+)/(\w+)/$#',
'base' => $base,
'model' => 'IDF_Views',
'method' => 'listProjects');
diff --git a/src/IDF/templates/idf/issues/search.html b/src/IDF/templates/idf/issues/search.html
index 4c0b720..4ffce24 100644
--- a/src/IDF/templates/idf/issues/search.html
+++ b/src/IDF/templates/idf/issues/search.html
@@ -22,11 +22,11 @@
{$tag.class}:{$tag.name}
{/blocktrans}
{else}
{* yes, this is duplicated from tags-cloud.html, but the code there cannot be easily overridden *}
-