Merge branch 'feature.issue-due-date' of https://github.com/treffynnon/Indefero into develop
@ -1,6 +1,10 @@
|
||||
# InDefero 1.3.2 - xxx xxx xx xx:xx 2012 UTC
|
||||
# InDefero 1.4 - xxx xxx xx xx:xx 2012 UTC
|
||||
|
||||
- ...
|
||||
## New Features
|
||||
|
||||
- Indefero can now record the due date of an issue and lets
|
||||
you filter and search by overdue issues (fixes issue 584,
|
||||
thanks to Simon Holywell!)
|
||||
|
||||
# InDefero 1.3.1 - Sun May 06 20:32 2012 UTC
|
||||
|
||||
|
@ -112,6 +112,12 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['due_dtime'] = new Pluf_Form_Field_Date(
|
||||
array('required' => false,
|
||||
'label' => __('Due date'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => 15,),
|
||||
));
|
||||
|
||||
$this->fields['relation_type0'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
@ -368,6 +374,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
||||
$issue->status = new IDF_Tag($_t[0]); // first one is the default
|
||||
$issue->owner = null;
|
||||
}
|
||||
$issue->due_dtime = $this->cleaned_data['due_dtime'];
|
||||
$issue->summary = trim($this->cleaned_data['summary']);
|
||||
$issue->create();
|
||||
foreach ($tags as $tag) {
|
||||
|
@ -103,6 +103,13 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$due_dtime = substr($this->issue->due_dtime, 0, 10);
|
||||
$this->fields['due_dtime'] = new Pluf_Form_Field_Date(
|
||||
array('required' => false,
|
||||
'label' => __('Due date'),
|
||||
'initial' => $due_dtime,
|
||||
'widget_attrs' => array('size' => 15,),
|
||||
));
|
||||
|
||||
$idx = 0;
|
||||
// note: clean_relation_type0 and clean_relation_issue0 already
|
||||
@ -266,6 +273,9 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
if (trim($this->issue->due_dtime) != trim($this->cleaned_data['due_dtime'])) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
@ -385,6 +395,9 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
||||
$changes['ow'] = (is_null($owner)) ? '---' : $owner->login;
|
||||
}
|
||||
if (trim($this->issue->due_dtime) != trim($this->cleaned_data['due_dtime'])) {
|
||||
$changes['du'] = Pluf_Template_dateFormat($this->cleaned_data['due_dtime']);
|
||||
}
|
||||
// Issue relations - additions
|
||||
foreach ($this->cleaned_data['_added_issue_relations'] as $verb => $ids) {
|
||||
$other_verb = $this->relation_types[$verb];
|
||||
@ -431,6 +444,7 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
$this->issue->summary = trim($this->cleaned_data['summary']);
|
||||
$this->issue->status = $status;
|
||||
$this->issue->owner = $owner;
|
||||
$this->issue->due_dtime = $this->cleaned_data['due_dtime'];
|
||||
}
|
||||
// Create the comment
|
||||
$comment = new IDF_IssueComment();
|
||||
|
@ -91,6 +91,13 @@ class IDF_Issue extends Pluf_Model
|
||||
'model' => 'IDF_Tag',
|
||||
'verbose' => __('labels'),
|
||||
),
|
||||
'due_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'is_null' => true,
|
||||
'verbose' => __('due date'),
|
||||
),
|
||||
'status' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
@ -149,11 +156,28 @@ class IDF_Issue extends Pluf_Model
|
||||
IDF_Search::remove($this);
|
||||
}
|
||||
|
||||
function restore()
|
||||
{
|
||||
// Note: If a due date has not been set then it should
|
||||
// be set to null and not a useless/confusing date so...
|
||||
if ('0000-00-00 00:00:00' === $this->due_dtime) {
|
||||
$this->due_dtime = null;
|
||||
}
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
// Note: If a due date is supplied then it must have
|
||||
// a time appended to it so that calculations of when
|
||||
// an issue falls overdue are accurate. In this case
|
||||
// 23:59:59 is added to signify the end of the day.
|
||||
if ($this->due_dtime and !empty($this->due_dtime)) {
|
||||
$this->due_dtime = date('Y-m-d 23:59:59',
|
||||
strtotime($this->due_dtime));
|
||||
}
|
||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,8 @@ class IDF_IssueComment extends Pluf_Model
|
||||
$out .= __('Status:'); break;
|
||||
case 'ow':
|
||||
$out .= __('Owner:'); break;
|
||||
case 'du':
|
||||
$out .= __('Due date:'); break;
|
||||
case 'lb':
|
||||
$out .= __('Labels:'); break;
|
||||
case 'rel':
|
||||
|
55
src/IDF/Migrations/26IssueDueDate.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** 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 ***** */
|
||||
|
||||
/**
|
||||
* Add the private column for the project.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_26IssueDueDate_up($params=null)
|
||||
{
|
||||
$table = Pluf::factory('IDF_Issue')->getSqlTable();
|
||||
$sql = array();
|
||||
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' ADD COLUMN "due_dtime" TIMESTAMP';
|
||||
$sql['MySQL'] = 'ALTER TABLE '.$table.' ADD COLUMN `due_dtime` DATETIME';
|
||||
$db = Pluf::db();
|
||||
$engine = Pluf::f('db_engine');
|
||||
if (!isset($sql[$engine])) {
|
||||
throw new Exception('SQLite complex migration not supported.');
|
||||
}
|
||||
$db->execute($sql[$engine]);
|
||||
}
|
||||
|
||||
function IDF_Migrations_26IssueDueDate_down($params=null)
|
||||
{
|
||||
$table = Pluf::factory('IDF_Issue')->getSqlTable();
|
||||
$sql = array();
|
||||
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' DROP COLUMN "due_dtime"';
|
||||
$sql['MySQL'] = 'ALTER TABLE '.$table.' DROP COLUMN `due_dtime`';
|
||||
$db = Pluf::db();
|
||||
$engine = Pluf::f('db_engine');
|
||||
if (!isset($sql[$engine])) {
|
||||
throw new Exception('SQLite complex migration not supported.');
|
||||
}
|
||||
$db->execute($sql[$engine]);
|
||||
|
||||
}
|
@ -201,6 +201,39 @@ GROUP BY uid";
|
||||
return $ownerStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of overdue issues.
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function getIssueCountByDueDate($due='overdue', $label=null, $ids=array())
|
||||
{
|
||||
$tags = array();
|
||||
foreach ($this->getTagsFromConfig('labels_issue_open', IDF_Form_IssueTrackingConf::init_open, 'Status') as $tag) {
|
||||
$tags[] = (int)$tag->id;
|
||||
}
|
||||
if (count($tags) == 0) return array();
|
||||
$sql = new Pluf_SQL(sprintf('project=%%s AND status IN (%s)', implode(', ', $tags)), array($this->id));
|
||||
if (!is_null($label)) {
|
||||
$sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
|
||||
$sql->SAnd($sql2);
|
||||
}
|
||||
if (count($ids) > 0) {
|
||||
$sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
|
||||
$sql->SAnd($sql2);
|
||||
}
|
||||
if('overdue' === $due) {
|
||||
$sql3 = new Pluf_SQL('due_dtime < NOW()');
|
||||
} else {
|
||||
$sql3 = new Pluf_SQL('due_dtime >= NOW()');
|
||||
}
|
||||
$sql->SAnd($sql3);
|
||||
$params = array('filter' => $sql->gen());
|
||||
if (!is_null($label)) { $params['view'] = 'join_tags'; }
|
||||
$gissue = new IDF_Issue();
|
||||
return $gissue->getCount($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of open/closed issues.
|
||||
*
|
||||
|
@ -42,6 +42,7 @@ class IDF_Views_Issue
|
||||
// Get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open');
|
||||
$closed = $prj->getIssueCountByStatus('closed');
|
||||
$overdue = $prj->getIssueCountByDueDate();
|
||||
// Paginator to paginate the issues
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
@ -61,9 +62,10 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -71,6 +73,7 @@ class IDF_Views_Issue
|
||||
'page_title' => $title,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'overdue' => $overdue,
|
||||
'issues' => $pag,
|
||||
'cloud' => 'issues',
|
||||
);
|
||||
@ -88,6 +91,7 @@ class IDF_Views_Issue
|
||||
{
|
||||
$tagStatistics = array();
|
||||
$ownerStatistics = array();
|
||||
$duedateStatistics = array();
|
||||
$status = array();
|
||||
$isTrackerEmpty = false;
|
||||
|
||||
@ -121,6 +125,14 @@ class IDF_Views_Issue
|
||||
}
|
||||
arsort($ownerStatistics);
|
||||
|
||||
// Issue due date statistics
|
||||
$overdue = $prj->getIssueCountByDueDate();
|
||||
$combined_opened = $overdue + $opened;
|
||||
$duedateStatistics = array();
|
||||
if ($combined_opened > 0) {
|
||||
$duedateStatistics = array($overdue, (int)(100 * $overdue / $combined_opened));
|
||||
}
|
||||
|
||||
// Issue class tag statistics
|
||||
$grouped_tags = $prj->getTagCloud();
|
||||
foreach ($grouped_tags as $class => $tags) {
|
||||
@ -154,6 +166,7 @@ class IDF_Views_Issue
|
||||
'project' => $prj,
|
||||
'tagStatistics' => $tagStatistics,
|
||||
'ownerStatistics' => $ownerStatistics,
|
||||
'duedateStatistics' => $duedateStatistics,
|
||||
'status' => $status,
|
||||
),
|
||||
$request);
|
||||
@ -187,9 +200,16 @@ class IDF_Views_Issue
|
||||
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array($prj->id));
|
||||
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
$sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array($prj->id));
|
||||
$nb_overdue = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
|
||||
// Generate a filter for the paginator
|
||||
switch ($match[2]) {
|
||||
case 'overdue':
|
||||
$title = sprintf(__('Watch List: Overdue Issues for %s'), (string) $prj);
|
||||
$summary = __('This table shows the overdue issues in your watch list for %s project.', (string) $prj);
|
||||
$f_sql = new Pluf_SQL('project=%s AND id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array($prj->id));
|
||||
break;
|
||||
case 'closed':
|
||||
$title = sprintf(__('Watch List: Closed Issues for %s'), (string) $prj);
|
||||
$summary = __('This table shows the closed issues in your watch list for %s project.', (string) $prj);
|
||||
@ -220,9 +240,10 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -231,6 +252,7 @@ class IDF_Views_Issue
|
||||
'page_title' => $title,
|
||||
'open' => $nb_open,
|
||||
'closed' => $nb_closed,
|
||||
'overdue' => $nb_overdue,
|
||||
'issues' => $pag,
|
||||
),
|
||||
$request);
|
||||
@ -270,9 +292,16 @@ class IDF_Views_Issue
|
||||
$nb_open = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
$sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $ctags).')', array());
|
||||
$nb_closed = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
$sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array());
|
||||
$nb_overdue = Pluf::factory('IDF_Issue')->getCount(array('filter'=>$sql->gen()));
|
||||
|
||||
// Generate a filter for the paginator
|
||||
switch ($match[1]) {
|
||||
case 'overdue':
|
||||
$title = sprintf(__('Watch List: Overdue Issues'));
|
||||
$summary = __('This table shows the overdue issues in your watch list.');
|
||||
$f_sql = new Pluf_SQL('id IN ('.$issue_ids.') AND status IN ('.implode(', ', $otags).') AND due_dtime < NOW()', array());
|
||||
break;
|
||||
case 'closed':
|
||||
$title = sprintf(__('Watch List: Closed Issues'));
|
||||
$summary = __('This table shows the closed issues in your watch list.');
|
||||
@ -302,9 +331,10 @@ class IDF_Views_Issue
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabelsUnknownProject', __('Summary')),
|
||||
array('project', 'Pluf_Paginator_FkToString', __('Project')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'project', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'project', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -312,6 +342,7 @@ class IDF_Views_Issue
|
||||
array('page_title' => $title,
|
||||
'open' => $nb_open,
|
||||
'closed' => $nb_closed,
|
||||
'overdue' => $nb_overdue,
|
||||
'issues' => $pag,
|
||||
),
|
||||
$request);
|
||||
@ -390,9 +421,10 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -443,6 +475,7 @@ class IDF_Views_Issue
|
||||
'preview' => $preview,
|
||||
'issue' => new IDF_Issue(),
|
||||
),
|
||||
self::getDateShortcuts(),
|
||||
self::autoCompleteArrays($prj)
|
||||
);
|
||||
if ($api == true) return $params;
|
||||
@ -461,7 +494,7 @@ class IDF_Views_Issue
|
||||
public function searchStatus($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
|
||||
$status = in_array($match[2], array('open', 'closed', 'overdue')) ? $match[2] : 'open';
|
||||
return $this->doSearch($request, $query, $status);
|
||||
}
|
||||
|
||||
@ -470,7 +503,7 @@ class IDF_Views_Issue
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$tag_id = intval($match[2]);
|
||||
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
|
||||
$status = in_array($match[3], array('open', 'closed', 'overdue')) ? $match[3] : 'open';
|
||||
return $this->doSearch($request, $query, $status, $tag_id);
|
||||
}
|
||||
|
||||
@ -490,6 +523,10 @@ class IDF_Views_Issue
|
||||
$title = sprintf(__('Search issues - %s'), $query);
|
||||
if ($status === 'closed') {
|
||||
$title = sprintf(__('Search closed issues - %s'), $query);
|
||||
} elseif ($status === 'overdue') {
|
||||
$title = sprintf(__('Search overdue issues - %s'), $query);
|
||||
$status = 'open';
|
||||
$overdue_status = true;
|
||||
}
|
||||
|
||||
// using Plufs ResultSet implementation here is inefficient, because
|
||||
@ -510,6 +547,10 @@ class IDF_Views_Issue
|
||||
'AND status IN ('.implode(', ', $otags).') '.
|
||||
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
|
||||
);
|
||||
if (isset($overdue_status)) {
|
||||
$sql2 = new Pluf_SQL('due_dtime < NOW()');
|
||||
$sql->SAnd($sql2);
|
||||
}
|
||||
$model = new IDF_Issue();
|
||||
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
|
||||
|
||||
@ -542,6 +583,7 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
));
|
||||
// disable paginating
|
||||
@ -562,6 +604,7 @@ class IDF_Views_Issue
|
||||
}
|
||||
|
||||
// get stats about the issues
|
||||
$overdue = $prj->getIssueCountByDueDate('overdue', $tag, $issue_ids);
|
||||
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
|
||||
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
|
||||
|
||||
@ -583,6 +626,7 @@ class IDF_Views_Issue
|
||||
'status' => $status,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'overdue' => $overdue,
|
||||
'tag' => $tag,
|
||||
'all_tags' => $grouped_tags,
|
||||
);
|
||||
@ -669,6 +713,7 @@ class IDF_Views_Issue
|
||||
'next_issue_id' => $next_issue_id,
|
||||
'related_issues' => $related_issues,
|
||||
),
|
||||
self::getDateShortcuts(),
|
||||
$arrays),
|
||||
$request);
|
||||
}
|
||||
@ -746,6 +791,7 @@ class IDF_Views_Issue
|
||||
// Get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open');
|
||||
$closed = $prj->getIssueCountByStatus('closed');
|
||||
$overdue = $prj->getIssueCountByDueDate();
|
||||
// Paginator to paginate the issues
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
@ -765,9 +811,10 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -776,6 +823,59 @@ class IDF_Views_Issue
|
||||
'page_title' => $title,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'overdue' => $overdue,
|
||||
'issues' => $pag,
|
||||
'cloud' => 'closed_issues',
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* View list of issues for a given project with a given status.
|
||||
*/
|
||||
public $listOverdue_precond = array('IDF_Precondition::accessIssues');
|
||||
public function listOverdue($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$status = __('Overdue');
|
||||
|
||||
$title = sprintf(__('%s %s Issues'), (string) $prj, (string) $status);
|
||||
// Get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open');
|
||||
$closed = $prj->getIssueCountByStatus('closed');
|
||||
$overdue = $prj->getIssueCountByDueDate();
|
||||
// Paginator to paginate the issues
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = __('This table shows the overdue issues.');
|
||||
$otags = $prj->getTagIdsByStatus('open');
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND due_dtime < NOW() AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
||||
$pag->action = array('IDF_Views_Issue::listOverdue', array($prj->shortname, $status));
|
||||
$pag->sort_order = array('due_dtime', 'DESC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('due_dtime');
|
||||
$pag->sort_link_title = true;
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
||||
array('project' => $prj,
|
||||
'page_title' => $title,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'overdue' => $overdue,
|
||||
'issues' => $pag,
|
||||
'cloud' => 'closed_issues',
|
||||
),
|
||||
@ -791,12 +891,17 @@ class IDF_Views_Issue
|
||||
$prj = $request->project;
|
||||
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
|
||||
$status = $match[3];
|
||||
if ($tag->project != $prj->id or !in_array($status, array('open', 'closed'))) {
|
||||
if ($tag->project != $prj->id or !in_array($status, array('open', 'closed', 'overdue'))) {
|
||||
throw new Pluf_HTTP_Error404();
|
||||
}
|
||||
if ($status == 'open') {
|
||||
$title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj,
|
||||
(string) $tag);
|
||||
} elseif ($status == 'overdue') {
|
||||
$title = sprintf(__('%1$s Overdue Issues with Label %2$s'), (string) $prj,
|
||||
(string) $tag);
|
||||
$overdue_status = true;
|
||||
$status = 'open';
|
||||
} else {
|
||||
$title = sprintf(__('%1$s Closed Issues with Label %2$s'),
|
||||
(string) $prj, (string) $tag);
|
||||
@ -804,6 +909,7 @@ class IDF_Views_Issue
|
||||
// Get stats about the open/closed issues having this tag.
|
||||
$open = $prj->getIssueCountByStatus('open', $tag);
|
||||
$closed = $prj->getIssueCountByStatus('closed', $tag);
|
||||
$overdue = $prj->getIssueCountByDueDate('overdue', $tag);
|
||||
// Paginator to paginate the issues
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->model_view = 'join_tags';
|
||||
@ -815,6 +921,9 @@ class IDF_Views_Issue
|
||||
$otags = $prj->getTagIdsByStatus($status);
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $tag->id));
|
||||
if (isset($overdue_status)) {
|
||||
$pag->forced_where->SAnd(new Pluf_SQL('due_dtime < NOW()'));
|
||||
}
|
||||
$pag->action = array('IDF_Views_Issue::listLabel', array($prj->shortname, $tag->id, $status));
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
@ -824,9 +933,10 @@ class IDF_Views_Issue
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('due_dtime', 'IDF_Views_Issue_DueDate', __('Due Date')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'due_dtime', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@ -842,6 +952,7 @@ class IDF_Views_Issue
|
||||
'open' => $open,
|
||||
'label' => $tag,
|
||||
'closed' => $closed,
|
||||
'overdue' => $overdue,
|
||||
'issues' => $pag,
|
||||
),
|
||||
$request);
|
||||
@ -1002,6 +1113,28 @@ class IDF_Views_Issue
|
||||
$auto['auto_relation_types'] = substr($auto['auto_relation_types'], 0, -2);
|
||||
return $auto;
|
||||
}
|
||||
|
||||
public static function getDateShortcuts()
|
||||
{
|
||||
return array(
|
||||
'date_shortcuts' => array(
|
||||
__('Soon') => array(
|
||||
__('Today') => date('Y-m-d'),
|
||||
__('Tomorrow') => date('Y-m-d', strtotime('tomorrow')),
|
||||
__('2 Days') => date('Y-m-d', strtotime('+2 days')),
|
||||
),
|
||||
__('Midterm') => array(
|
||||
__('Friday') => date('Y-m-d', strtotime('next friday')),
|
||||
__('1 Week') => date('Y-m-d', strtotime('+1 week')),
|
||||
__('A Fortnight') => date('Y-m-d', strtotime('+2 week')),
|
||||
),
|
||||
__('Longterm') => array(
|
||||
__('End of the Month') => date('Y-m-d', strtotime('last day of this month')),
|
||||
__('1 Month') => date('Y-m-d', strtotime('+1 month')),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1015,6 +1148,16 @@ function IDF_Views_Issue_SummaryAndLabelsUnknownProject($field, $issue, $extra='
|
||||
return IDF_Views_Issue_SummaryAndLabels ($field, $issue, $extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date value for the Due Date table column
|
||||
*/
|
||||
function IDF_Views_Issue_DueDate($field, $issue, $extra='')
|
||||
{
|
||||
if($issue->$field) {
|
||||
return Pluf_Template_dateFormat($issue->$field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the summary of an issue, then on a new line, display the
|
||||
* list of labels with a link to a view "by label only".
|
||||
@ -1037,8 +1180,12 @@ function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
|
||||
$s = '<img style="vertical-align: text-bottom;" src="'.Pluf_Template_Tag_MediaUrl::url('/idf/img/star.png').'" alt="'.__('On your watch list.').'" /> ';
|
||||
}
|
||||
$out = '';
|
||||
if ('' != $issue->due_dtime and (time() >= strtotime($issue->due_dtime)) and
|
||||
in_array($issue->status, $issue->get_project()->getTagIdsByStatus('open'))) {
|
||||
$out = ' <span class="overdue">' . __('overdue') . '</span>';
|
||||
}
|
||||
if (count($tags)) {
|
||||
$out = '<br /><span class="note">'.implode(', ', $tags).'</span>';
|
||||
$out .= '<br /><span class="note">'.implode(', ', $tags).'</span>';
|
||||
}
|
||||
return $s.sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($issue->summary)).$out;
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ $cfg['idf_strong_key_check'] = false;
|
||||
# submitted as value of the HTTP header 'Post-Commit-Hook-Hmac' during
|
||||
# such a request. Since newer versions of Indefero use the same authentication
|
||||
# mechanism (based on the same secret key) for other web hooks of the same
|
||||
# project as well, the name of this HTTP header was no longer appropriate
|
||||
# project as well, the name of this HTTP header was no longer appropriate
|
||||
# and as such changed to simply 'Web-Hook-Hmac'.
|
||||
#
|
||||
# Setting the following configuration option to 'compat' now restores the
|
||||
@ -533,7 +533,7 @@ $cfg['activity_section_weights'] = array(
|
||||
'wiki' => 2,
|
||||
'downloads' => 1,
|
||||
'review' => 1,
|
||||
);
|
||||
);
|
||||
|
||||
# Here you can define the timespan in days how long the activity calculation
|
||||
# process should look into the history to get meaningful activity values for
|
||||
@ -544,5 +544,4 @@ $cfg['activity_section_weights'] = array(
|
||||
# high enough to show a proper activity index for those projects as well.
|
||||
$cfg['activity_lookback'] = 7;
|
||||
|
||||
return $cfg;
|
||||
|
||||
return $cfg;
|
@ -163,6 +163,11 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/status/(\w+)/$#',
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'listStatus');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/due/overdue/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'listOverdue');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/label/(\d+)/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
|
@ -25,6 +25,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
|
||||
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
|
||||
<!--[if lt IE 7]>
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
|
||||
@ -32,6 +33,7 @@
|
||||
{block extraheader}{/block}
|
||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
|
||||
{appversion}
|
||||
</head>
|
||||
<body>
|
||||
|
@ -25,6 +25,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
|
||||
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
|
||||
<!--[if lt IE 7]>
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
|
||||
@ -32,6 +33,7 @@
|
||||
{block extraheader}{/block}
|
||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
|
||||
{appversion}
|
||||
</head>
|
||||
<body>
|
||||
|
@ -25,6 +25,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/yui.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/style.css'}" />
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/jquery-ui-1.8.18.custom.css'}" />
|
||||
<link rel="icon" type="image/png" href="{media '/idf/img/favicon.png'}" />
|
||||
<!--[if lt IE 7]>
|
||||
<link rel="stylesheet" type="text/css" href="{media '/idf/css/ie6.css'}" />
|
||||
@ -32,6 +33,7 @@
|
||||
{block extraheader}{/block}
|
||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.7.2.min.js'}"></script>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-ui-1.8.18.custom.min.js'}"></script>
|
||||
{appversion}
|
||||
</head>
|
||||
<body>
|
||||
|
@ -10,8 +10,10 @@
|
||||
{block context}
|
||||
{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 'overdue_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'overdue')}
|
||||
{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><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>
|
||||
{/blocktrans}
|
||||
<p><strong>{trans 'Label:'}</strong>
|
||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
|
@ -63,6 +63,24 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.due_dtime.labelTag}:</th>
|
||||
<td>{if $form.f.due_dtime.errors}{$form.f.due_dtime.fieldErrors}{/if}
|
||||
{$form.f.due_dtime|unsafe}
|
||||
<div id="due_dtime_wrapper">
|
||||
<a href="#" id="due_dtime_shortcut_link">Date shortcuts… ▾</a>
|
||||
{if $date_shortcuts}
|
||||
<dl id="due_dtime_more_shortcuts" style="display: none">
|
||||
{foreach $date_shortcuts as $time_span => $shortcuts}
|
||||
<dt>{$time_span}</dt>
|
||||
{foreach $shortcuts as $title => $date}
|
||||
<dd><a href="javascript:void(0);" rel="{$date}" class="due_dtime_shortcut">{$title}</a></dd>
|
||||
{/foreach}
|
||||
{/foreach}
|
||||
</dl>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<tr>
|
||||
<th>{$form.f.relation_type0.labelTag}:</th>
|
||||
<td>
|
||||
{if $form.f.relation_type0.errors}{$form.f.relation_type0.fieldErrors}{/if}
|
||||
@ -108,7 +126,21 @@
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_summary').focus();{literal}
|
||||
$(document).ready(function(){
|
||||
|
||||
$("#id_due_dtime").datepicker({
|
||||
changeYear: true,
|
||||
changeMonth: true,
|
||||
yearRange: '-0:+5',
|
||||
constrainInput: false,
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
$('#due_dtime_wrapper').mouseover(function(){
|
||||
$('#due_dtime_more_shortcuts').show();
|
||||
}).mouseout(function(){
|
||||
$('#due_dtime_more_shortcuts').hide();
|
||||
});
|
||||
$(".due_dtime_shortcut").click(function(){
|
||||
$('#id_due_dtime').val($(this).attr('rel'));
|
||||
});
|
||||
// Hide the upload forms, we insert before the first attach file
|
||||
// row an "Attach File" little link.
|
||||
// We hide all the rows.
|
||||
|
@ -14,7 +14,7 @@
|
||||
</ul>{/if}
|
||||
{if $c.changes}
|
||||
{foreach $c.changes as $w => $v}
|
||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
|
||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}</strong>
|
||||
{if $w == 'lb' or $w == 'rel'}
|
||||
{foreach $v as $t => $ls}
|
||||
{foreach $ls as $l}
|
||||
|
@ -7,6 +7,8 @@
|
||||
{block context}
|
||||
{aurl 'open_url', 'IDF_Views_Issue::forgeWatchList', array('open')}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::forgeWatchList', array('closed')}
|
||||
{aurl 'overdue_url', 'IDF_Views_Issue::forgeWatchList', array('overdue')}
|
||||
{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}
|
||||
{/block}
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||
<p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
|
||||
{/block}
|
@ -10,8 +10,10 @@
|
||||
{block context}
|
||||
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
||||
{aurl 'overdue_url', 'IDF_Views_Issue::listOverdue', array($project.shortname, 'Overdue', 'overdue')}
|
||||
{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}
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||
<p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
|
||||
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
|
||||
{include 'idf/tags-cloud.html'}
|
||||
{/block}
|
||||
|
@ -6,6 +6,7 @@
|
||||
{trans 'Project:'} {$project.name|safe}
|
||||
{trans 'Status:'} {$issue.get_status.name|safe}
|
||||
{trans 'Reported by:'} {$issue.get_submitter|safe}
|
||||
{if $issue.due_dtime}{trans 'Due date:'} {$issue.due_dtime|date|safe}{/if}
|
||||
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
|
||||
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
|
||||
{/foreach}{/if}
|
||||
|
@ -6,6 +6,7 @@
|
||||
{trans 'Project:'} {$project.name|safe}
|
||||
{trans 'Status:'} {$issue.get_status.name}
|
||||
{trans 'Reported by:'} {$issue.get_submitter|safe}
|
||||
{if $issue.due_dtime}{trans 'Due date:'} {$issue.due_dtime|date|safe}{/if}
|
||||
{trans 'URL:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
|
||||
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
|
||||
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
|
||||
@ -16,7 +17,7 @@
|
||||
|
||||
{if strlen($c.content) > 0}{$c.content|safe}{/if}{if $c.changedIssue()}
|
||||
{foreach $c.changes as $w => $v}
|
||||
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if} {if $w == 'lb' or $w == 'rel'}{foreach $v as $t => $ls}{foreach $ls as $l}{if $t == 'rem'}-{/if}{$l} {/foreach}{/foreach}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0}
|
||||
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if} {if $w == 'lb' or $w == 'rel'}{foreach $v as $t => $ls}{foreach $ls as $l}{if $t == 'rem'}-{/if}{$l} {/foreach}{/foreach}{else}{$v}{/if}{/foreach}{/if}{assign $attachments = $c.get_attachment_list()}{if $attachments.count() > 0}
|
||||
|
||||
{trans 'Attachments:'}{foreach $attachments as $a}
|
||||
- {$a.filename|safe} - {$a.filesize|ssize}
|
||||
|
@ -12,6 +12,8 @@
|
||||
{block context}
|
||||
{aurl 'open_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'closed')}
|
||||
{aurl 'overdue_url', 'IDF_Views_Issue::watchList', array($project.shortname, 'overdue')}
|
||||
{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}
|
||||
{/block}
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||
<p><span>Overdue:</span> <a href="{$overdue_url}">{$overdue}</a></p>{/blocktrans}
|
||||
{/block}
|
@ -10,13 +10,16 @@
|
||||
{block context}
|
||||
{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)}
|
||||
{aurl 'overdue_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'overdue'), 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)}
|
||||
{aurl 'overdue_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'overdue'), 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}
|
||||
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
|
||||
<p>Found overdue issues: <a href="{$overdue_url}">{$overdue}</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}
|
||||
|
@ -103,6 +103,34 @@
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if $duedateStatistics}
|
||||
<div>
|
||||
<h2>{blocktrans}Unresolved: By Due Date{/blocktrans}</h2>
|
||||
<table class='issue-summary'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="name">
|
||||
{aurl 'url', 'IDF_Views_Issue::listOverdue', array($project.shortname, 'overdue', 'due')}
|
||||
<a href="{$url}">{blocktrans}Overdue{/blocktrans}</a>
|
||||
</td>
|
||||
<td class="count">{$duedateStatistics[0]}</td>
|
||||
<td class="graph">
|
||||
<table class='graph'>
|
||||
<tbody><tr>
|
||||
<td style="width:{$duedateStatistics[1] * 0.8 + 1}%" class="graph-color" valign="center">
|
||||
<div class="colour-bar"></div>
|
||||
</td>
|
||||
<td class="graph-percent">{$duedateStatistics[1]}%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/block}
|
||||
|
@ -40,7 +40,7 @@
|
||||
{if $i> 0 and $c.changedIssue()}
|
||||
<div class="issue-changes">
|
||||
{foreach $c.changes as $w => $v}
|
||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
|
||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'du'}{trans 'Due date:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}{if $w == 'rel'}{trans 'Relations:'}{/if}</strong>
|
||||
{if $w == 'lb' or $w == 'rel'}
|
||||
{foreach $v as $t => $ls}
|
||||
{foreach $ls as $l}
|
||||
@ -128,6 +128,24 @@
|
||||
{$form.f.owner|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<th>{$form.f.due_dtime.labelTag}:</th>
|
||||
<td>{if $form.f.due_dtime.errors}{$form.f.due_dtime.fieldErrors}{/if}
|
||||
{$form.f.due_dtime|unsafe}
|
||||
<div id="due_dtime_wrapper">
|
||||
<a href="#" id="due_dtime_shortcut_link">Date shortcuts… ▾</a>
|
||||
{if $date_shortcuts}
|
||||
<dl id="due_dtime_more_shortcuts" style="display: none">
|
||||
{foreach $date_shortcuts as $time_span => $shortcuts}
|
||||
<dt>{$time_span}</dt>
|
||||
{foreach $shortcuts as $title => $date}
|
||||
<dd><a href="javascript:void(0);" rel="{$date}" class="due_dtime_shortcut">{$title}</a></dd>
|
||||
{/foreach}
|
||||
{/foreach}
|
||||
</dl>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<tr>
|
||||
<tr>
|
||||
<th>{$form.f.relation_type0.labelTag}:</th>
|
||||
<td>
|
||||
@ -180,6 +198,9 @@
|
||||
<strong>{trans 'Owner:'}</strong> {showuser $issue.get_owner(), $request}
|
||||
</p>{/if}
|
||||
{if $interested > 0}<p><strong>{trans 'Followed by:'}</strong> {blocktrans $interested}{$interested} person{plural}{$interested} persons{/blocktrans}</p>{/if}
|
||||
{if $issue.due_dtime}
|
||||
<p><strong>{trans 'Due Date:'}</strong> {$issue.due_dtime|date}</p>
|
||||
{/if}
|
||||
{assign $tags = $issue.get_tags_list()}{if $tags.count()}
|
||||
<p>
|
||||
<strong>{trans 'Labels:'}</strong><br />
|
||||
@ -209,7 +230,21 @@
|
||||
<script type="text/javascript">
|
||||
{literal}
|
||||
$(document).ready(function(){
|
||||
|
||||
$("#id_due_dtime").datepicker({
|
||||
changeYear: true,
|
||||
changeMonth: true,
|
||||
yearRange: '-0:+5',
|
||||
constrainInput: false,
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
$('#due_dtime_wrapper').mouseover(function(){
|
||||
$('#due_dtime_more_shortcuts').show();
|
||||
}).mouseout(function(){
|
||||
$('#due_dtime_more_shortcuts').hide();
|
||||
});
|
||||
$(".due_dtime_shortcut").click(function(){
|
||||
$('#id_due_dtime').val($(this).attr('rel'));
|
||||
});
|
||||
// Hide the upload forms, we insert before the first attach file
|
||||
// row an "Attach File" little link.
|
||||
// We hide all the rows.
|
||||
|
354
www/media/idf/css/jquery-ui-1.8.18.custom.css
vendored
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.18
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
|
||||
.ui-helper-clearfix:after { clear: both; }
|
||||
.ui-helper-clearfix { zoom: 1; }
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||
|
||||
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.18
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
|
||||
*/
|
||||
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
|
||||
.ui-widget .ui-widget { font-size: 1em; }
|
||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
|
||||
.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(/media/idf/img/jquery-ui/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
|
||||
.ui-widget-content a { color: #222222; }
|
||||
.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(/media/idf/img/jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
|
||||
.ui-widget-header a { color: #222222; }
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(/media/idf/img/jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
|
||||
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
|
||||
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(/media/idf/img/jquery-ui/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
||||
.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(/media/idf/img/jquery-ui/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
||||
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
|
||||
.ui-widget :active { outline: none; }
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(/media/idf/img/jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
|
||||
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
||||
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(/media/idf/img/jquery-ui/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
|
||||
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
|
||||
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
|
||||
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
||||
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
||||
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { width: 16px; height: 16px; background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_222222_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(/media/idf/img/jquery-ui/ui-icons_888888_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_454545_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_454545_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_2e83ff_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(/media/idf/img/jquery-ui/ui-icons_cd0a0a_256x240.png); }
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-off { background-position: -96px -144px; }
|
||||
.ui-icon-radio-on { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { background: #aaaaaa url(/media/idf/img/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
|
||||
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(/media/idf/img/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
|
||||
* jQuery UI Datepicker 1.8.18
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Datepicker#theming
|
||||
*/
|
||||
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
||||
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
||||
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
||||
.ui-datepicker .ui-datepicker-prev { left:2px; }
|
||||
.ui-datepicker .ui-datepicker-next { right:2px; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
||||
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
||||
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
||||
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
||||
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
||||
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
||||
.ui-datepicker select.ui-datepicker-month,
|
||||
.ui-datepicker select.ui-datepicker-year { width: 49%;}
|
||||
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
||||
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
||||
.ui-datepicker td { border: 0; padding: 1px; }
|
||||
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi { width:auto; }
|
||||
.ui-datepicker-multi .ui-datepicker-group { float:left; }
|
||||
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
||||
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
|
||||
|
||||
/* RTL support */
|
||||
.ui-datepicker-rtl { direction: rtl; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
|
||||
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
|
||||
.ui-datepicker-cover {
|
||||
display: none; /*sorry for IE5*/
|
||||
display/**/: block; /*sorry for IE5*/
|
||||
position: absolute; /*must have*/
|
||||
z-index: -1; /*must have*/
|
||||
filter: mask(); /*must have*/
|
||||
top: -4px; /*must have*/
|
||||
left: -4px; /*must have*/
|
||||
width: 200px; /*must have*/
|
||||
height: 200px; /*must have*/
|
||||
}
|
@ -184,6 +184,14 @@ table.recent-issues td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.recent-issues td span.overdue {
|
||||
font-weight: bold;
|
||||
background-color: #c00;
|
||||
color: #fff;
|
||||
padding: 0 2px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
table.recent-issues tfoot th {
|
||||
text-align: right;
|
||||
}
|
||||
@ -317,6 +325,72 @@ div.issue-submit-info h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#due_dtime_wrapper {
|
||||
float: right;
|
||||
width: 350px;
|
||||
position: relative;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
#due_dtime_shortcut_link {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#due_dtime_wrapper > a {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-top: -3px;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#due_dtime_more_shortcuts {
|
||||
display: none;
|
||||
background: #A5E26A;
|
||||
border-top: 0;
|
||||
position: absolute;
|
||||
margin: 1px 0 0;
|
||||
z-index: 1000;
|
||||
top: 1.1em;
|
||||
-moz-border-radius: 0 0 3px 3px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
-moz-box-shadow: 0 10px 20px #333;
|
||||
-webkit-box-shadow: 0 10px 20px #333;
|
||||
box-shadow: 0 10px 20px #333;
|
||||
max-height: 400px;
|
||||
min-width: 145px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 0 5px 5px;
|
||||
}
|
||||
|
||||
#due_dtime_more_shortcuts dt {
|
||||
font-weight: bold;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#due_dtime_more_shortcuts dd {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
#due_dtime_more_shortcuts a {
|
||||
text-decoration: none;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
#due_dtime_more_shortcuts a:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#due_dtime_wrapper:hover > a {
|
||||
background: #A5E26A;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#due_dtime_wrapper:hover a {
|
||||
color: #2E3436;
|
||||
}
|
||||
|
||||
span.label {
|
||||
color: #204a87;
|
||||
padding-left: 0.5em;
|
||||
@ -610,7 +684,7 @@ span.ctrl-char {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* special formatting for the TAB character: make it wider, so it is rendered more properly */
|
||||
/* special formatting for the TAB character: make it wider, so it is rendered more properly */
|
||||
span.ctrl-char[title="0x09"] {
|
||||
width: 24px;
|
||||
}
|
||||
@ -701,7 +775,7 @@ table.diff-linecounts.right-hidden tr > td + td {
|
||||
table.diff-contents td {
|
||||
line-height: 12px;
|
||||
padding: 2px;
|
||||
font-size: 90%;
|
||||
font-size: 90%;
|
||||
border: none;
|
||||
white-space: pre;
|
||||
}
|
||||
@ -723,7 +797,7 @@ table.diff-contents td:hover > span.ctrl-char {
|
||||
}
|
||||
|
||||
table.diff-contents td.added > span.ctrl-char {
|
||||
background: #0A0;
|
||||
background: #0A0;
|
||||
}
|
||||
|
||||
table.diff-contents td.removed > span.ctrl-char {
|
||||
@ -857,7 +931,7 @@ div.deprecated-page {
|
||||
}
|
||||
|
||||
li.old-rev {
|
||||
font-style: italic;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.delp {
|
||||
|
BIN
www/media/idf/img/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png
Normal file
After Width: | Height: | Size: 180 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_flat_75_ffffff_40x100.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png
Normal file
After Width: | Height: | Size: 120 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_glass_65_ffffff_1x400.png
Normal file
After Width: | Height: | Size: 105 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_glass_75_dadada_1x400.png
Normal file
After Width: | Height: | Size: 111 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png
Normal file
After Width: | Height: | Size: 110 B |
BIN
www/media/idf/img/jquery-ui/ui-bg_glass_95_fef1ec_1x400.png
Normal file
After Width: | Height: | Size: 119 B |
After Width: | Height: | Size: 101 B |
BIN
www/media/idf/img/jquery-ui/ui-icons_222222_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
www/media/idf/img/jquery-ui/ui-icons_2e83ff_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
www/media/idf/img/jquery-ui/ui-icons_454545_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
www/media/idf/img/jquery-ui/ui-icons_888888_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
www/media/idf/img/jquery-ui/ui-icons_cd0a0a_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |