Merge branch 'develop' of projects.ceondo.com:indefero into develop

feature.diff-whitespace
Thomas Keller 2011-10-09 02:25:03 +02:00
commit ffc49b9ea6
17 changed files with 323 additions and 99 deletions

View File

@ -7,12 +7,19 @@ or newer to properly run this version of Indefero!
- Indefero's issue tracker can now bi-directionally link issues with variable, configurable - Indefero's issue tracker can now bi-directionally link issues with variable, configurable
terms, such as "is related to", "is blocked by" or "is duplicated by" (issue 638) terms, such as "is related to", "is blocked by" or "is duplicated by" (issue 638)
- When you search for issues, the results can further be refined by issue state (open or closed)
and label (partially implements issue 548)
- Mercurial source views now show parent revisions (if any) and detailed change information - Mercurial source views now show parent revisions (if any) and detailed change information
- Subversion source views now show detailed change information (issue 622) - Subversion source views now show detailed change information (issue 622)
- File download URLs now contain the file name rather than the upload id; old links still work though (issues 559 and 686) - File download URLs now contain the file name rather than the upload id; old links still work though (issues 559 and 686)
- Display monotone file and directory attributes in the tree and file view - Display monotone file and directory attributes in the tree and file view
(needs a monotone with an interface version of 13.1 or newer) (needs a monotone with an interface version of 13.1 or newer)
- The context area is now kept in view when a page scrolls down several pages - The context area is now kept in view when a page scrolls down several pages
- Add a summary section to the issue tracker with statistics about open/close issues,
tags of open issue, and count of open tickets for each owner.
- Improved home page with an customizable icon for each project.
- The download section provide MD5 for each files.
- Wiki page have now a css for printer output (issue 713)
## Bugfixes ## Bugfixes
@ -41,6 +48,8 @@ or newer to properly run this version of Indefero!
- Indefero no longer displays an empty parents paragraph in the commit view for root revisions of - Indefero no longer displays an empty parents paragraph in the commit view for root revisions of
a git repository a git repository
- Indefero now only shows the tags of the closed and not the open issues in the closed issues list - Indefero now only shows the tags of the closed and not the open issues in the closed issues list
- Avatar URL generation use correctly the configuration (issue 732)
- Git cron job doesn't erase anymore manually added keys (issue 247)
## Documentation ## Documentation

View File

@ -132,7 +132,7 @@ class IDF_Project extends Pluf_Model
} }
return $projects[0]; return $projects[0];
} }
/** /**
* Returns the number of open/closed issues. * Returns the number of open/closed issues.
* *
@ -167,7 +167,7 @@ GROUP BY uid";
$key = ($v['id'] === '-1') ? null : $v['id']; $key = ($v['id'] === '-1') ? null : $v['id'];
$ownerStatistics[$key] = (int)$v['nb']; $ownerStatistics[$key] = (int)$v['nb'];
} }
arsort($ownerStatistics); arsort($ownerStatistics);
return $ownerStatistics; return $ownerStatistics;
@ -178,9 +178,10 @@ GROUP BY uid";
* *
* @param string Status ('open'), 'closed' * @param string Status ('open'), 'closed'
* @param IDF_Tag Subfilter with a label (null) * @param IDF_Tag Subfilter with a label (null)
* @param array Restrict further to a list of ids
* @return int Count * @return int Count
*/ */
public function getIssueCountByStatus($status='open', $label=null) public function getIssueCountByStatus($status='open', $label=null, $ids=array())
{ {
switch ($status) { switch ($status) {
case 'open': case 'open':
@ -203,12 +204,48 @@ GROUP BY uid";
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id)); $sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
$sql->SAnd($sql2); $sql->SAnd($sql2);
} }
if (count($ids) > 0) {
$sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
$sql->SAnd($sql2);
}
$params = array('filter' => $sql->gen()); $params = array('filter' => $sql->gen());
if (!is_null($label)) { $params['view'] = 'join_tags'; } if (!is_null($label)) { $params['view'] = 'join_tags'; }
$gissue = new IDF_Issue(); $gissue = new IDF_Issue();
return $gissue->getCount($params); return $gissue->getCount($params);
} }
/**
* Get the tags for a specific list of issues.
*
* @param string Status ('open') or 'closed'
* @param array A list of issue ids
* @return array An array of tag objects
*/
public function getTagsByIssues($issue_ids=array())
{
// make the below query always a valid one
if (count($issue_ids) == 0) $issue_ids[] = 0;
$assocTable = $this->_con->pfx.'idf_issue_idf_tag_assoc';
$query = sprintf(
'SELECT DISTINCT idf_tag_id FROM %s '.
'WHERE idf_issue_id IN (%s) '.
'GROUP BY idf_tag_id',
$assocTable, implode(',', $issue_ids)
);
$db = Pluf::db();
$dbData = $db->select($query);
$ids = array(0);
foreach ($dbData as $data) {
$ids[] = $data['idf_tag_id'];
}
$sql = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
$model = new IDF_Tag();
return $model->getList(array('filter' => $sql->gen()));
}
/** /**
* Get the open/closed tag ids as they are often used when doing * Get the open/closed tag ids as they are often used when doing
* listings. * listings.
@ -415,7 +452,11 @@ GROUP BY uid";
foreach ($this->_con->select($sql) as $idc) { foreach ($this->_con->select($sql) as $idc) {
$tag = new IDF_Tag($idc['id']); $tag = new IDF_Tag($idc['id']);
$tag->nb_use = $idc['nb_use']; $tag->nb_use = $idc['nb_use'];
$tags[] = $tag; // group by class
if (!array_key_exists($tag->class, $tags)) {
$tags[$tag->class] = array();
}
$tags[$tag->class][] = $tag;
} }
return new Pluf_Template_ContextVars($tags); return new Pluf_Template_ContextVars($tags);
} }

View File

@ -319,13 +319,11 @@ class IDF_Views_Download
$pag->no_results_text = __('No downloads were found.'); $pag->no_results_text = __('No downloads were found.');
$pag->sort_order = array('creation_dtime', 'DESC'); $pag->sort_order = array('creation_dtime', 'DESC');
$pag->setFromRequest($request); $pag->setFromRequest($request);
$tags = $prj->getTagCloud('downloads');
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html', return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
array( array(
'page_title' => $title, 'page_title' => $title,
'label' => $tag, 'label' => $tag,
'downloads' => $pag, 'downloads' => $pag,
'tags' => $tags,
'dlabel' => $dtag, 'dlabel' => $dtag,
), ),
$request); $request);

View File

@ -111,17 +111,21 @@ class IDF_Views_Issue
foreach ($owners as $user => $nb) { foreach ($owners as $user => $nb) {
if ($user === '') { if ($user === '') {
$key = __('Not assigned'); $key = __('Not assigned');
$login = null;
} else { } else {
$obj = Pluf::factory('Pluf_User')->getOne(array('filter'=>'id='.$user)); $obj = Pluf::factory('Pluf_User')->getOne(array('filter'=>'id='.$user));
$key = $obj->first_name . ' ' . $obj->last_name; $key = $obj->first_name . ' ' . $obj->last_name;
$login = $obj->login;
} }
$ownerStatistics[$key] = array($nb, (int)(100 * $nb / $opened)); $ownerStatistics[$key] = array($nb, (int)(100 * $nb / $opened), $login);
} }
// Issue class tag statistics // Issue class tag statistics
$tags = $prj->getTagCloud(); $grouped_tags = $prj->getTagCloud();
foreach ($tags as $t) { foreach ($grouped_tags as $class => $tags) {
$tagStatistics[$t->class][$t->name] = array($t->nb_use, $t->id); foreach ($tags as $tag) {
$tagStatistics[$class][$tag->name] = array($tag->nb_use, $tag->id);
}
} }
foreach($tagStatistics as $k => $v) { foreach($tagStatistics as $k => $v) {
$nbIssueInClass = 0; $nbIssueInClass = 0;
@ -315,42 +319,55 @@ class IDF_Views_Issue
* *
* Only open issues are shown. * Only open issues are shown.
*/ */
public $myIssues_precond = array('IDF_Precondition::accessIssues', public $userIssues_precond = array('IDF_Precondition::accessIssues');
'Pluf_Precondition::loginRequired'); public function userIssues($request, $match)
public function myIssues($request, $match)
{ {
$prj = $request->project; $prj = $request->project;
$sql = new Pluf_SQL('login=%s', array($match[2]));
$user = Pluf::factory('Pluf_User')->getOne(array('filter' => $sql->gen()));
if ($user === null) {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$otags = $prj->getTagIdsByStatus('open'); $otags = $prj->getTagIdsByStatus('open');
$ctags = $prj->getTagIdsByStatus('closed'); $ctags = $prj->getTagIdsByStatus('closed');
if (count($otags) == 0) $otags[] = 0; if (count($otags) == 0) $otags[] = 0;
if (count($ctags) == 0) $ctags[] = 0; if (count($ctags) == 0) $ctags[] = 0;
switch ($match[2]) { switch ($match[3]) {
case 'submit': case 'submit':
$title = sprintf(__('My Submitted %s Issues'), (string) $prj); $titleFormat = __('%s %s Submitted %s Issues');
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id)); $f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
break; break;
case 'submitclosed': case 'submitclosed':
$title = sprintf(__('My Closed Submitted %s Issues'), (string) $prj); $titleFormat = __('%s %s Closed Submitted %s Issues');
$f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id)); $f_sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
break; break;
case 'ownerclosed': case 'ownerclosed':
$title = sprintf(__('My Closed Working %s Issues'), (string) $prj); $titleFormat = __('%s %s Closed Working %s Issues');
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id)); $f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
break; break;
default: default:
$title = sprintf(__('My Working %s Issues'), (string) $prj); $titleFormat = __('%s %s Working %s Issues');
$f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id)); $f_sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
break; break;
} }
$title = sprintf($titleFormat,
$user->first_name,
$user->last_name,
(string) $prj);
// Get stats about the issues // Get stats about the issues
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id)); $sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
$nb_submit = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_submit = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $request->user->id)); $sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $user->id));
$nb_owner = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_owner = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
// Closed issues // Closed issues
$sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id)); $sql = new Pluf_SQL('project=%s AND submitter=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
$nb_submit_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_submit_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
$sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $request->user->id)); $sql = new Pluf_SQL('project=%s AND owner=%s AND status IN ('.implode(', ', $ctags).')', array($prj->id, $user->id));
$nb_owner_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen())); $nb_owner_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
// Paginator to paginate the issues // Paginator to paginate the issues
@ -361,7 +378,7 @@ class IDF_Views_Issue
'current_user' => $request->user); 'current_user' => $request->user);
$pag->summary = __('This table shows the open issues.'); $pag->summary = __('This table shows the open issues.');
$pag->forced_where = $f_sql; $pag->forced_where = $f_sql;
$pag->action = array('IDF_Views_Issue::myIssues', array($prj->shortname, $match[2])); $pag->action = array('IDF_Views_Issue::userIssues', array($prj->shortname, $match[2]));
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted $pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
$pag->sort_reverse_order = array('modif_dtime'); $pag->sort_reverse_order = array('modif_dtime');
$pag->sort_link_title = true; $pag->sort_link_title = true;
@ -376,9 +393,10 @@ class IDF_Views_Issue
$pag->items_per_page = 10; $pag->items_per_page = 10;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
return Pluf_Shortcuts_RenderToResponse('idf/issues/my-issues.html', return Pluf_Shortcuts_RenderToResponse('idf/issues/userIssues.html',
array('project' => $prj, array('project' => $prj,
'page_title' => $title, 'page_title' => $title,
'login' => $user->login,
'nb_submit' => $nb_submit, 'nb_submit' => $nb_submit,
'nb_owner' => $nb_owner, 'nb_owner' => $nb_owner,
'nb_submit_closed' => $nb_submit_closed, 'nb_submit_closed' => $nb_submit_closed,
@ -431,45 +449,142 @@ class IDF_Views_Issue
public $search_precond = array('IDF_Precondition::accessIssues'); public $search_precond = array('IDF_Precondition::accessIssues');
public function search($request, $match) public function search($request, $match)
{
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
return $this->doSearch($request, $query, 'open');
}
public $searchStatus_precond = array('IDF_Precondition::accessIssues');
public function searchStatus($request, $match)
{
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
return $this->doSearch($request, $query, $status);
}
public $searchLabel_precond = array('IDF_Precondition::accessIssues');
public function searchLabel($request, $match)
{
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
$tag_id = intval($match[2]);
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
return $this->doSearch($request, $query, $status, $tag_id);
}
private function doSearch($request, $query, $status, $tag_id=null)
{ {
$prj = $request->project; $prj = $request->project;
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') { if (trim($query) == '') {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', $url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', array($prj->shortname));
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url); return new Pluf_HTTP_Response_Redirect($url);
} }
$q = $request->REQUEST['q'];
$title = sprintf(__('Search Issues - %s'), $q); $tag = null;
$issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Issue')); if ($tag_id !== null) {
if (count($issues) > 100) { $tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $tag_id);
// no more than 100 results as we do not care
$issues->results = array_slice($issues->results, 0, 100);
} }
$title = sprintf(__('Search issues - %s'), $query);
if ($status === 'closed') {
$title = sprintf(__('Search closed issues - %s'), $query);
}
// using Plufs ResultSet implementation here is inefficient, because
// it makes a SELECT for each item and does not allow for further
// filtering neither, so we just return the ids and filter by them
// and other things in the next round
$results = IDF_Search::mySearch($query, $prj, 'IDF_Issue');
$issue_ids = array(0);
foreach ($results as $result) {
$issue_ids[] = $result['model_id'];
}
$otags = $prj->getTagIdsByStatus($status);
if (count($otags) == 0) $otags[] = 0;
$sql = new Pluf_SQL(
'id IN ('.implode(',', $issue_ids).') '.
'AND status IN ('.implode(', ', $otags).') '.
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
);
$model = new IDF_Issue();
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
// we unfortunately loose the original sort order,
// so we manually have to apply it here again
$sorted_issues = new ArrayObject();
$filtered_issue_ids = array(0);
foreach ($issue_ids as $issue_id) {
foreach ($issues as $issue) {
if ($issue->id != $issue_id)
continue;
if (array_key_exists($issue_id, $sorted_issues))
continue;
$sorted_issues[$issue_id] = $issue;
$filtered_issue_ids[] = $issue_id;
}
}
$pag = new Pluf_Paginator(); $pag = new Pluf_Paginator();
$pag->items = $issues;
$pag->class = 'recent-issues'; $pag->class = 'recent-issues';
$pag->item_extra_props = array('project_m' => $prj, $pag->items = $sorted_issues;
'shortname' => $prj->shortname, $pag->item_extra_props = array(
'current_user' => $request->user); 'project_m' => $prj,
'shortname' => $prj->shortname,
'current_user' => $request->user
);
$pag->summary = __('This table shows the found issues.'); $pag->summary = __('This table shows the found issues.');
$pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
$pag->extra_classes = array('a-c', '', 'a-c', ''); $pag->extra_classes = array('a-c', '', 'a-c', '');
$list_display = array( $pag->configure(array(
'id' => __('Id'), 'id' => __('Id'),
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')), array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')), array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')), array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
); ));
$pag->configure($list_display); // disable paginating
$pag->items_per_page = 100; $pag->items_per_page = PHP_INT_MAX;
$pag->no_results_text = __('No issues were found.'); $pag->no_results_text = __('No issues were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
$params = array('page_title' => $title,
'issues' => $pag,
'q' => $q,
);
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
if ($tag_id === null) {
$pag->action = array('IDF_Views_Issue::searchStatus',
array($prj->shortname, $status),
array('q'=> $query),
);
} else {
$pag->action = array('IDF_Views_Issue::searchLabel',
array($prj->shortname, $tag_id, $status),
array('q'=> $query),
);
}
// get stats about the issues
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
// query the available tags for this search result
$all_tags = $prj->getTagsByIssues($filtered_issue_ids);
$grouped_tags = array();
foreach ($all_tags as $atag) {
// group by class
if (!array_key_exists($atag->class, $grouped_tags)) {
$grouped_tags[$atag->class] = array();
}
$grouped_tags[$atag->class][] = $atag;
}
$params = array(
'page_title' => $title,
'issues' => $pag,
'query' => $query,
'status' => $status,
'open' => $open,
'closed' => $closed,
'tag' => $tag,
'all_tags' => $grouped_tags,
);
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
} }
public $view_precond = array('IDF_Precondition::accessIssues'); public $view_precond = array('IDF_Precondition::accessIssues');
@ -617,6 +732,13 @@ class IDF_Views_Issue
{ {
$prj = $request->project; $prj = $request->project;
$status = $match[2]; $status = $match[2];
if (mb_strtolower($status) == 'open') {
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$title = sprintf(__('%s Closed Issues'), (string) $prj); $title = sprintf(__('%s Closed Issues'), (string) $prj);
// Get stats about the issues // Get stats about the issues
$open = $prj->getIssueCountByStatus('open'); $open = $prj->getIssueCountByStatus('open');

View File

@ -152,13 +152,11 @@ class IDF_Views_Wiki
$pag->items_per_page = 25; $pag->items_per_page = 25;
$pag->no_results_text = __('No documentation pages were found.'); $pag->no_results_text = __('No documentation pages were found.');
$pag->setFromRequest($request); $pag->setFromRequest($request);
$tags = $prj->getTagCloud('wiki');
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html', return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
array( array(
'page_title' => $title, 'page_title' => $title,
'label' => $tag, 'label' => $tag,
'pages' => $pag, 'pages' => $pag,
'tags' => $tags,
'dlabel' => $dtag, 'dlabel' => $dtag,
), ),
$request); $request);

View File

@ -117,7 +117,7 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
'base' => $base, 'base' => $base,
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
'method' => 'index'); 'method' => 'index');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#', $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#',
'base' => $base, 'base' => $base,
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
@ -128,6 +128,16 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
'method' => 'search'); 'method' => 'search');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/status/(\w+)/$#',
'base' => $base,
'model' => 'IDF_Views_Issue',
'method' => 'searchStatus');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/label/(\d+)/(\w+)/$#',
'base' => $base,
'model' => 'IDF_Views_Issue',
'method' => 'searchLabel');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#', $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
'base' => $base, 'base' => $base,
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
@ -153,10 +163,10 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/create/$#',
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
'method' => 'create'); 'method' => 'create');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/my/(\w+)/$#', $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(.*)/(\w+)/$#',
'base' => $base, 'base' => $base,
'model' => 'IDF_Views_Issue', 'model' => 'IDF_Views_Issue',
'method' => 'myIssues'); 'method' => 'userIssues');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#', $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#',
'base' => $base, 'base' => $base,

View File

@ -4,10 +4,10 @@
<div id="sub-tabs"> <div id="sub-tabs">
<a {if $inSummaryIssues}class="active" {/if}href="{url 'IDF_Views_Issue::summary', array($project.shortname)}">{trans 'Summary'}</a> <a {if $inSummaryIssues}class="active" {/if}href="{url 'IDF_Views_Issue::summary', array($project.shortname)}">{trans 'Summary'}</a>
| <a {if $inOpenIssues}class="active" {/if}href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Open Issues'}</a> | <a {if $inOpenIssues}class="active" {/if}href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Open Issues'}</a>
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a> {if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}">{trans 'My Issues'}</a>
| <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} | | <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} |
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get"> <form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
<input accesskey="4" type="text" value="{$q}" name="q" size="20" /> <input accesskey="4" type="text" value="{$query}" name="q" size="20" />
<input type="submit" name="s" value="{trans 'Search'}" /> <input type="submit" name="s" value="{trans 'Search'}" />
</form> </form>
{if $inIssue} | {if $inIssue} |

View File

@ -8,16 +8,15 @@
{/block} {/block}
{block context} {block context}
<p><strong>{trans 'Label:'}</strong>
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')} {aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')} {aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p> {blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p> <p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
{/blocktrans}{if $completion} {/blocktrans}
<p><strong>{trans 'Label:'}</strong>
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
{if $completion}
<p><strong>{trans 'Completion:'}</strong> {$completion}</p> <p><strong>{trans 'Completion:'}</strong> {$completion}</p>
{/if} {/if}
{/block} {/block}

View File

@ -8,5 +8,25 @@
{/block} {/block}
{block context} {block context}
<p><strong>{trans 'Found issues:'}</strong> {$issues.nb_items}</p> {aurl 'open_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'), array('q' => $query)}
{aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)}
{if $tag != null}
{aurl 'open_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'), array('q' => $query)}
{aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)}
{/if}
{blocktrans}
<p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
{if $tag !== null}
{blocktrans}<p><strong>Label:</strong>
<a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans}
{else}
{* yes, this is duplicated from tags-cloud.html, but the code there cannot be easily overridden *}
<div id="tagscloud" class="smaller"><dl>{foreach $all_tags as $class => $labels}
<dt class="label">{$class}</dt>
{foreach $labels as $idx => $label}
{aurl 'url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $label.id, $status), array('q'=> $query)}
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
{/foreach}{/foreach}</dl></p>
{/if}
{/block} {/block}

View File

@ -71,7 +71,12 @@
<tbody> <tbody>
{foreach $ownerStatistics as $key => $value} {foreach $ownerStatistics as $key => $value}
<tr> <tr>
<td class="name">{$key}</td> <td class="name">
{if !empty($value[2])}
{aurl 'url', 'IDF_Views_Issue::userIssues', array($project.shortname, $value[2], 'owner')}
<a href="{$url}">{$key}</a>
{else}{$key}{/if}
</td>
<td class="count">{$value[0]}</td> <td class="count">{$value[0]}</td>
<td class="graph"> <td class="graph">
<table class='graph'> <table class='graph'>

View File

@ -1,5 +1,5 @@
{extends "idf/issues/base.html"} {extends "idf/issues/base.html"}
{block docclass}yui-t2{assign $inMyIssues = true}{/block} {block docclass}yui-t2{if $user.login == $login}{assign $inMyIssues = true}{/if}{/block}
{block body} {block body}
{$issues.render} {$issues.render}
{if !$user.isAnonymous()} {if !$user.isAnonymous()}
@ -8,10 +8,10 @@
{/block} {/block}
{block context} {block context}
{aurl 'owner_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'owner')} {aurl 'owner_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'owner')}
{aurl 'submit_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')} {aurl 'submit_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'submit')}
{aurl 'owner_closed_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'ownerclosed')} {aurl 'owner_closed_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'ownerclosed')}
{aurl 'submit_closed_url', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submitclosed')} {aurl 'submit_closed_url', 'IDF_Views_Issue::userIssues', array($project.shortname, $login, 'submitclosed')}
<p><strong>{trans 'Submitted issues:'}</strong> <a href="{$submit_url}">{$nb_submit}</a> <p><strong>{trans 'Submitted issues:'}</strong> <a href="{$submit_url}">{$nb_submit}</a>
{if $nb_submit_closed}<br /><span class="helptext">{blocktrans $nb_submit_closed}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{plural}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{/blocktrans}</span>{/if}</p> {if $nb_submit_closed}<br /><span class="helptext">{blocktrans $nb_submit_closed}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{plural}See the <a href="{$submit_closed_url}">{$nb_submit_closed} closed</a>.{/blocktrans}</span>{/if}</p>
{if $nb_owner > 0} {if $nb_owner > 0}

View File

@ -10,8 +10,8 @@
{if $hasWikiAccess}{hotkey 'Shift+o', 'IDF_Views_Wiki::index', array($project.shortname)}{/if} {if $hasWikiAccess}{hotkey 'Shift+o', 'IDF_Views_Wiki::index', array($project.shortname)}{/if}
{if $hasSourceAccess}{hotkey 'Shift+s', 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}{/if} {if $hasSourceAccess}{hotkey 'Shift+s', 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}{/if}
{if $hasIssuesAccess and !$user.isAnonymous()} {if $hasIssuesAccess and !$user.isAnonymous()}
{hotkey 'Shift+m', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')} {hotkey 'Shift+m', 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}
{hotkey 'Shift+w', 'IDF_Views_Issue::myIssues', array($project.shortname, 'owner')} {hotkey 'Shift+w', 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'owner')}
{/if}{/if} //--> {/if}{/if} //-->
</script> </script>

View File

@ -4,7 +4,7 @@
<div id="sub-tabs"> <div id="sub-tabs">
<a {if $inOpenReviews}class="active" {/if}href="{url 'IDF_Views_Review::index', array($project.shortname)}">{trans 'Open Reviews'}</a> {* <a {if $inOpenReviews}class="active" {/if}href="{url 'IDF_Views_Review::index', array($project.shortname)}">{trans 'Open Reviews'}</a> {*
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>{/if} | {if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::userIssues', array($project.shortname, $user.login, 'submit')}">{trans 'My Issues'}</a>{/if} |
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get"> <form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
<input accesskey="4" type="text" value="{$q}" name="q" size="20" /> <input accesskey="4" type="text" value="{$q}" name="q" size="20" />
<input type="submit" name="s" value="{trans 'Search'}" /> <input type="submit" name="s" value="{trans 'Search'}" />

View File

@ -5,17 +5,4 @@
{if !$user.isAnonymous()} {if !$user.isAnonymous()}
{aurl 'url', 'IDF_Views_Review::create', array($project.shortname)} {aurl 'url', 'IDF_Views_Review::create', array($project.shortname)}
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if} <p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if}
{/block} {/block}
{block context}
{*
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
{assign $class = ''}{assign $i = 0}
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
<a href="{$url}" class="label">{$label.name}</a>,{assign $class = $label.class}{assign $i = $i + 1}{/foreach}</p>
*}{/block}

View File

@ -1,8 +1,6 @@
{assign $class = ''}{assign $i = 0} <div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $class => $labels}
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $label} <dt class="label">{$class}</dt>
{foreach $labels as $idx => $label}
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')} {aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
{if $class != $label.class}<dt class="label">{$label.class}</dt>{assign $i = 0}{/if} <dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
<dd><a href="{$url}" class="label">{$label.name},</a></dd> {/foreach}{/foreach}</dl></p>
{assign $class = $label.class}
{assign $i = $i + 1}
{/foreach}</dl></p>

View File

@ -1,5 +1,10 @@
{extends "idf/wiki/base.html"} {extends "idf/wiki/base.html"}
{block extraheader}{if $oldrev}<meta name="ROBOTS" content="NOINDEX" />{/if}{/block}
{block extraheader}
{if $oldrev}<meta name="ROBOTS" content="NOINDEX" />{/if}
<link rel="stylesheet" type="text/css" media="print" href="{media '/idf/css/print-wiki.css'}" />
{/block}
{block docclass}yui-t3{assign $inView=true}{/block} {block docclass}yui-t3{assign $inView=true}{/block}
{block body} {block body}

View File

@ -0,0 +1,32 @@
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
#hd, #ft, #context {
display: none;
}
.yui-t3 #yui-main .yui-b {
margin: 0;
}
#wiki-toc {
float: none;
}