This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".
The branch, master has been updated
via 1188e98adadc839690bcf9d5876ff055160c7529 (commit)
via 8c661763217d24cea406aa21de4ee1e7b8ad2b84 (commit)
via 1830188100c4593800b271b87b0a9a1c01705286 (commit)
via fd53dbbe12f14cbbc3b46304923ed34ab242824b (commit)
via b16cafc79d7c2ca2fd0de39b3ab8dc9ccc54a6d2 (commit)
via 283838b1ba70566e7ed4ce36215c7dbb9f061c95 (commit)
via a0a3bf0af69a78dc172bef6186ba9baa29119f2d (commit)
from 9cb2fb1b401deec39d3db5679017b2d862fadb3a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1188e98adadc839690bcf9d5876ff055160c7529
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun May 31 13:12:40 2015 +0300
JS code is polished
diff --git a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
index 30ee859..4686189 100644
--- a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
+++ b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
@@ -256,9 +256,6 @@ class TaskBoardColumnSource extends Error {
$target_column = taskboard_column_get_object(
$this->getTargetColumnID() );
$columns = $this->getTaskboard()->getColumns();
-
- error_log( count($columns) . ' ' .
$target_column->getOrder() );
-
if( $target_column->getOrder() == count($columns) ) {
// final column, so set remaining cost to 0
$remaining_cost = 0;
diff --git a/src/plugins/taskboard/common/views/releases/burndown.php
b/src/plugins/taskboard/common/views/releases/burndown.php
index 170bf8c..3e241c6 100644
--- a/src/plugins/taskboard/common/views/releases/burndown.php
+++ b/src/plugins/taskboard/common/views/releases/burndown.php
@@ -108,54 +108,54 @@ foreach( $release_snapshots as $snapshot ) {
{
axesDefaults: {
pad : 1
- },
+ },
seriesColors: [ '#000', '#DDDDDD', '#00FA9A',
'#B22222' ],
legend: {
- show: true,
- location: 'ne',
- xoffset: 12,
- yoffset: 12
- },
+ show: true,
+ location: 'ne',
+ xoffset: 12,
+ yoffset: 12
+ },
axes : {
- xaxis : {
+ xaxis : {
renderer :
jQuery.jqplot.DateAxisRenderer,
tickRenderer:
jQuery.jqplot.CanvasAxisTickRenderer,
tickOptions:{
- angle: -90,
- fontSize : '1.3em',
- formatString : '%Y-%m-%d'
- },
- numberTicks: <?php echo
count($xaxisData) - 2; ?>,
- min: <?php echo
$release->getStartDate() * 1000; ?>,
- max: <?php echo $release->getEndDate()
* 1000; ?>
+ angle: -90,
+ fontSize : '1.3em',
+ formatString :
'%Y-%m-%d'
+ },
+ numberTicks: <?php echo
count($xaxisData) - 2; ?>,
+ min: <?php echo
$release->getStartDate() * 1000; ?>,
+ max: <?php echo
$release->getEndDate() * 1000; ?>
},
yaxis : {
autoscale:true,
min : 0,
- label: "<?php echo _('Completed
tasks') ?>" ,
- labelRenderer:
jQuery.jqplot.CanvasAxisLabelRenderer,
- labelOptions:{
- fontSize : '12px'
- }
+ label: "<?php echo _('Completed
tasks') ?>" ,
+ labelRenderer:
jQuery.jqplot.CanvasAxisLabelRenderer,
+ labelOptions:{
+ fontSize : '12px'
+ }
},
- y2axis: {
- autoscale:true,
- min : 0,
- tickOptions:{
- isMinorTick: true,
- formatString: "%.1f <?php echo _('m/d')
?>"
- }
- }
+ y2axis: {
+ autoscale:true,
+ min : 0,
+ tickOptions:{
+ isMinorTick: true,
+ formatString: "%.1f <?php echo
_('m/d') ?>"
+ }
+ }
},
- series:[
- { show : false }, // to indicates all
dates only
+ series:[
+ { show : false }, // to indicate all
dates
{ label : "<?php echo _('Ideal
burndown') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } },
{ label : "<?php echo _('Remaining
tasks') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 },
yaxis: 'yaxis' },
{ label : "<?php echo _('Remaining
efforts') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } ,
yaxis:'y2axis' }
],
highlighter: {
- show: true,
- sizeAdjust: 8
+ show: true,
+ sizeAdjust: 8
},
cursor: {
show: false
diff --git a/src/plugins/taskboard/www/js/agile-board.js
b/src/plugins/taskboard/www/js/agile-board.js
index dcaf08c..d55b7fc 100644
--- a/src/plugins/taskboard/www/js/agile-board.js
+++ b/src/plugins/taskboard/www/js/agile-board.js
@@ -185,8 +185,8 @@ function drawBoardProgress() {
// show progress by cost
html += '<table>';
html += '<tr><td width="' + parseInt( 100 / aPhases.length ) +
'%" style="padding: 0;">' + gMessages.progressByCost + ':</td><td
style="padding: 0;">';
+ html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;" title="' + gMessages['completedCost'] + '">' +
totalCostCompleted + '</div>';
html += '<div class="agile-board-progress-bar-remains"
style="width: ' + ( 100 - wt ) + '%;" title="' + gMessages['remainingCost'] +
'">' + totalCostRemaining + '</div>';
- html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;" title="' + gMessages['completedCost'] + '">' +
totalCostCompleted + '</div>';
html += '</td></tr><table>';
}
@@ -482,7 +482,7 @@ function initEditable() {
}
});
}
- });
+ });
}
commit 8c661763217d24cea406aa21de4ee1e7b8ad2b84
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun May 31 10:00:36 2015 +0300
Remaining cost is set to 0 when card is dropped on the last column
diff --git a/src/plugins/taskboard/TODO.txt b/src/plugins/taskboard/TODO.txt
index 9a6048e..7a26292 100644
--- a/src/plugins/taskboard/TODO.txt
+++ b/src/plugins/taskboard/TODO.txt
@@ -10,14 +10,14 @@
- DONE View - filter by assigned persons
- DONE Releases are based either on US or on tasks
- DONE View - indicators - progress by tasks number
-- API - configured fields support in mapped tasks ('estimated_dev_effort',
'remaining_dev_effort', 'user_story' )
-- View - indicators - progress by tasks cost (if efforts fields are configured)
+- DONE API - configured fields support in mapped tasks
('estimated_dev_effort', 'remaining_dev_effort', 'user_story' )
+- DONE View - indicators - progress by tasks cost (if efforts fields are
configured)
- DONE Admin - releases management
- View - auto ref rate support
- Admin - auto ref rate support
- Admin - adapters - coloring support
- View - adapters - coloring support (for GT)
- View - colors by extrafield (for GT)
-- View - indicators - burndown chart
+- DONE View - indicators - burndown chart
- View - indicators - velocity calculation
- Improve taskboard initialization - columns by default?
diff --git a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
index feae4ba..30ee859 100644
--- a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
+++ b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
@@ -248,8 +248,24 @@ class TaskBoardColumnSource extends Error {
if( $this->getAutoassign() ) {
$assigned_to = user_getid();
}
+
- $msg = $this->getTaskboard()->TrackersAdapter->updateTask(
$task,$assigned_to, $this->getTargetResolution() );
+ $remaining_cost = NULL;
+ if( $this->getTaskboard()->getRemainingCostField() ) {
+ // set 0 to remainin cost if target column is a last one
+ $target_column = taskboard_column_get_object(
$this->getTargetColumnID() );
+
+ $columns = $this->getTaskboard()->getColumns();
+
+ error_log( count($columns) . ' ' .
$target_column->getOrder() );
+
+ if( $target_column->getOrder() == count($columns) ) {
+ // final column, so set remaining cost to 0
+ $remaining_cost = 0;
+ }
+ }
+
+ $msg = $this->getTaskboard()->TrackersAdapter->updateTask(
$task, $assigned_to, $this->getTargetResolution(), NULL, NULL, $remaining_cost
);
if($msg) {
$msg = _('Tracker error')._(': ').$msg;
}
diff --git
a/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
b/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
index f6283c9..17a723f 100644
--- a/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
+++ b/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
@@ -322,7 +322,7 @@ class TaskBoardBasicAdapter {
*
* @return string error message in case of fail
*/
- function updateTask(&$artifact, $assigned_to, $resolution, $title =
NULL, $description = NULL) {
+ function updateTask(&$artifact, $assigned_to, $resolution, $title =
NULL, $description = NULL, $remaining_cost=NULL ) {
if (!$assigned_to) {
$assigned_to = $artifact->getAssignedTo();
}
@@ -341,6 +341,17 @@ class TaskBoardBasicAdapter {
}
}
+ if($remaining_cost!==NULL) {
+ $remaining_cost_alias =
$this->TaskBoard->getRemainingCostField();
+
+ if($remaining_cost_alias) {
+ if (array_key_exists($remaining_cost_alias,
$fields_ids)){
+ $remaining_cost_field_id =
$fields_ids[$remaining_cost_alias];
+ $extra_fields[ $remaining_cost_field_id
] = $remaining_cost;
+ }
+ }
+ }
+
if (!$title) {
$title =
htmlspecialchars_decode($artifact->getSummary());
}
commit 1830188100c4593800b271b87b0a9a1c01705286
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun May 31 08:59:42 2015 +0300
Fix for snapshot saved completed_man_days calculation
diff --git a/src/plugins/taskboard/common/TaskBoardRelease.class.php
b/src/plugins/taskboard/common/TaskBoardRelease.class.php
index cdeafa9..03d65de 100644
--- a/src/plugins/taskboard/common/TaskBoardRelease.class.php
+++ b/src/plugins/taskboard/common/TaskBoardRelease.class.php
@@ -275,15 +275,17 @@ class TaskBoardRelease extends Error {
if( $tsk['phase_id'] ==
$columns[$i]->getID() ) {
if( $i + 1 == $_columns_num ) {
// last column, so -
completed task
-
$ret['completed_tasks']++;
- if(
$tsk['estimated_dev_effort'] ) {
-
$ret['completed_man_days'] += ( (float) $tsk['estimated_dev_effort'] - (float)
$tsk['remaining_dev_effort'] );
- }
+
$ret['completed_tasks']++;
} else {
// incomplete task, so
incomplete US
$completed_us = false;
}
$ret['tasks']++;
+
+ if(
$tsk['estimated_dev_effort'] ) {
+
$ret['completed_man_days'] += ( (float) $tsk['estimated_dev_effort'] - (float)
$tsk['remaining_dev_effort'] );
+ }
+
if(
$tsk['estimated_dev_effort'] ) {
$ret['man_days'] +=
(float) $tsk['estimated_dev_effort'];
}
commit fd53dbbe12f14cbbc3b46304923ed34ab242824b
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun May 31 08:49:28 2015 +0300
taskboard: cherry-pick ac3f849a1611a3eb8ce10c5cc8a91a5a18ecb70c
diff --git a/src/plugins/taskboard/common/TaskBoardRelease.class.php
b/src/plugins/taskboard/common/TaskBoardRelease.class.php
index a368859..cdeafa9 100644
--- a/src/plugins/taskboard/common/TaskBoardRelease.class.php
+++ b/src/plugins/taskboard/common/TaskBoardRelease.class.php
@@ -247,22 +247,26 @@ class TaskBoardRelease extends Error {
}
/**
- * Save current taskboard snapshot. So, we can have a history of
release implementation,
- * that could be used for different indicators calculation.
+ * Get release volume - number of total
*
- * @param int Snapshot unix date time
- * @return boolean success.
+ * @return array hash with user_stories, tasks, story_points,
man_days key
*/
- function saveSnapshot($snapshot_datetime) {
- $user_stories =
$this->Taskboard->getUserStories($this->getTitle());
+ function getVolume() {
+ $user_stories =
$this->Taskboard->getUserStories($this->getTitle());
$columns = $this->Taskboard->getColumns($this->getTitle());
$_columns_num = count($columns);
- $_completed_user_stories = 0;
- $_completed_tasks = 0;
- $_completed_story_points = 0;
- $_completed_man_days = 0;
-
+ $ret = array(
+ 'user_stories' => 0,
+ 'completed_user_stories' => 0,
+ 'tasks' => 0,
+ 'completed_tasks' => 0,
+ 'story_points' => 0,
+ 'completed_story_points' => 0,
+ 'man_days'=> 0,
+ 'completed_man_days'=> 0,
+ );
+
foreach( $user_stories as $us ) {
$completed_us = true;
@@ -270,26 +274,45 @@ class TaskBoardRelease extends Error {
foreach( $us['tasks'] as $tsk ) {
if( $tsk['phase_id'] ==
$columns[$i]->getID() ) {
if( $i + 1 == $_columns_num ) {
- // last column, so-
completed task
- $_completed_tasks++;
+ // last column, so -
completed task
+
$ret['completed_tasks']++;
+ if(
$tsk['estimated_dev_effort'] ) {
+
$ret['completed_man_days'] += ( (float) $tsk['estimated_dev_effort'] - (float)
$tsk['remaining_dev_effort'] );
+ }
} else {
// incomplete task, so
incomplete US
$completed_us = false;
}
+ $ret['tasks']++;
+ if(
$tsk['estimated_dev_effort'] ) {
+ $ret['man_days'] +=
(float) $tsk['estimated_dev_effort'];
+ }
}
}
-
}
-
+
if( $completed_us ) {
- $_completed_user_stories++;
+ $ret['completed_user_stories']++;
// TODO $_completed_story_points += ...
}
+ $ret['user_stories']++;
}
-
-
+
+ return $ret;
+ }
+
+ /**
+ * Save current taskboard snapshot. So, we can have a history of
release implementation,
+ * that could be used for different indicators calculation.
+ *
+ * @param int Snapshot unix date time
+ * @return boolean success.
+ */
+ function saveSnapshot($snapshot_datetime) {
+ $release_volume = $this->getVolume();
+
$res = db_query_params(
- 'SELECT taskboard_release_snapshot_id FROM
plugin_taskboard_releases_snapshots WHERE taskboard_release_id=$1 AND
snapshot_date=$2',
+ 'SELECT taskboard_release_snapshot_id FROM
plugin_taskboard_releases_snapshots WHERE taskboard_release_id=$1 AND
snapshot_date=$2',
array ($this->getID(), $snapshot_datetime )
);
@@ -297,20 +320,20 @@ class TaskBoardRelease extends Error {
$this->setError('TaskBoardRelease: Cannot get release
snapshot');
return false;
}
-
+
$row = db_fetch_array($res);
db_free_result($res);
-
+
if( $row ) {
$res = db_query_params(
- 'UPDATE
plugin_taskboard_releases_snapshots
+ 'UPDATE
plugin_taskboard_releases_snapshots
SET completed_user_stories=$1,
completed_tasks=$2, completed_story_points=$3, completed_man_days=$4
WHERE taskboard_release_snapshot_id=$5',
array(
-
$_completed_user_stories,
- $_completed_tasks,
- 0, //TODO
- 0, //TODO
+
$release_volume['completed_user_stories'],
+
$release_volume['completed_tasks'],
+
$release_volume['completed_story_points'],
+
$release_volume['completed_man_days'],
intval($row['taskboard_release_snapshot_id'])
)
);
@@ -325,10 +348,10 @@ class TaskBoardRelease extends Error {
array(
$this->getID(),
$snapshot_datetime,
-
$_completed_user_stories,
- $_completed_tasks,
- 0, //TODO
- 0 //TODO
+
$release_volume['completed_user_stories'],
+
$release_volume['completed_tasks'],
+
$release_volume['completed_story_points'],
+
$release_volume['completed_man_days'],
)
);
if (!$res) {
@@ -339,4 +362,31 @@ class TaskBoardRelease extends Error {
return true;
}
+
+ /**
+ * Get current release snapshots
+ *
+ * @return array
+ */
+ function getSnapshots() {
+ $ret = array();
+
+ $res = db_query_params(
+ 'SELECT snapshot_date, completed_user_stories,
completed_tasks, completed_story_points, completed_man_days
+ FROM plugin_taskboard_releases_snapshots WHERE
taskboard_release_id=$1 ORDER BY snapshot_date',
+ array ($this->getID() )
+ );
+
+ if (!$res) {
+ $this->setError('TaskBoardRelease: Cannot get release
snapshots');
+ return false;
+ }
+
+ while( $row = db_fetch_array($res) ) {
+ $ret[] = $row;
+ }
+ db_free_result($res);
+
+ return $ret;
+ }
}
diff --git a/src/plugins/taskboard/common/views/admin/edit_column.php
b/src/plugins/taskboard/common/views/admin/edit_column.php
index 480dfa0..2f89bb2 100644
--- a/src/plugins/taskboard/common/views/admin/edit_column.php
+++ b/src/plugins/taskboard/common/views/admin/edit_column.php
@@ -94,7 +94,6 @@ if ($column_id) {
echo $HTML->multiTableRow(array(), $cells);
$cells = array();
$cells[][] = html_e('strong', array(), _('Alert message'));
- error_log($drop_rules_by_default->getAlertText());
$cells[][] = html_e('textarea', array('name' => 'alert', 'cols'
=> 79, 'rows' => 5), htmlspecialchars($drop_rules_by_default->getAlertText()),
false);
echo $HTML->multiTableRow(array(), $cells);
echo $HTML->listTableBottom();
diff --git a/src/plugins/taskboard/common/views/releases/burndown.php
b/src/plugins/taskboard/common/views/releases/burndown.php
new file mode 100644
index 0000000..170bf8c
--- /dev/null
+++ b/src/plugins/taskboard/common/views/releases/burndown.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * Copyright (C) 2015 Vitaliy Pylypiv <[email protected]>
+ *
+ * This file is part of FusionForge.
+ *
+ * FusionForge 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.
+ *
+ * FusionForge 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+global $group_id, $group, $taskboard;
+
+$release_id = getIntFromRequest('release_id', NULL);
+
+$release = new TaskBoardRelease( $taskboard, $release_id );
+
+html_use_jqueryjqplotpluginCanvas();
+html_use_jqueryjqplotplugindateAxisRenderer();
+html_use_jqueryjqplotpluginhighlighter();
+
+$taskboard->header(
+ array(
+ 'title' => _('Taskboard for
').$group->getPublicName()._(': '). _('Releases')._(': ')._('Burndown
chart')._(': ').$release->getTitle() ,
+ 'pagename' => _('Releases')._(': ')._('Burndown
chart')._(': ').$release->getTitle(),
+ 'sectionvals' => array($group->getPublicName()),
+ 'group' => $group_id
+ )
+ );
+
+if ($taskboard->isError()) {
+ echo $HTML->error_msg($taskboard->getErrorMessage());
+} else {
+ echo html_e('div', array('id' => 'messages', 'style' => 'display:
none;'), '', false);
+}
+
+// $xaxisData is used to have an every date on the X axis
+$xaxisData = array();
+$chartDate = $release->getStartDate();
+while( $chartDate <= $release->getEndDate() ) {
+ $xaxisData[] = array( date( 'r', $chartDate) , 0);
+ $chartDate += 86400;
+}
+
+$release_volume = $release->getVolume();
+
+// ideal burndown
+$dataIdeal = array(
+ array( $release->getStartDate() * 1000, $release_volume['tasks']),
+ array( $release->getEndDate() * 1000, 0)
+);
+
+$release_snapshots = $release->getSnapshots();
+$dataRemainingTasks = array();
+$dataRemainingEfforts = array();
+
+foreach( $release_snapshots as $snapshot ) {
+ if( count($dataRemainingTasks) == 0 && $snapshot['snapshot_date'] !=
$release->getStartDate() ) {
+ // initialize start point if snapshot is missing for the first
day
+ $dataRemainingTasks[] = array( $release->getStartDate() * 1000,
$release_volume['tasks'] );
+ $dataRemainingEfforts[] = array( $release->getStartDate() *
1000, $release_volume['man_days'] );
+ }
+
+ $dataRemainingTasks[] = array( $snapshot['snapshot_date'] * 1000, (
$release_volume['tasks'] - $snapshot['completed_tasks'] ) );
+ $dataRemainingEfforts[] = array( $snapshot['snapshot_date'] * 1000, (
$release_volume['man_days'] - $snapshot['completed_man_days'] ) );
+}
+
+
+
+?>
+<div id="taskboard-burndown-chart-nav">
+ <button id="taskboard-view-btn"><?php echo _('Taskboard'); ?></button>
+ <br/>
+</div>
+
+<figure>
+ <figcaption><?php echo _("Burndown chart") . ' : ' .
$release->getTitle() ?></figcaption>
+ <div id="taskboard-burndown-chart">
+ </div>
+</figure>
+
+<script>
+ var burndownChart;
+ var xaxisData = <?php echo json_encode( $xaxisData ); ?>;
+ var dataRemainingTasks = <?php echo json_encode( $dataRemainingTasks );
?>;
+ var dataRemainingEfforts = <?php echo json_encode(
$dataRemainingEfforts ); ?>;
+ var dataRemainingIdeal = <?php echo json_encode( $dataIdeal ); ?>;
+
+ jQuery( document ).ready(function( $ ) {
+ jQuery('#taskboard-view-btn').click( function ( e ) {
+ window.location = '<?php echo util_make_url
('/plugins/'.$pluginTaskboard->name.'?group_id='. $group_id . '&_release=' .
$release_id ); ?>';
+ e.preventDefault();
+ });
+
+ burndownChart = jQuery.jqplot(
+ 'taskboard-burndown-chart',
+ [ xaxisData, dataRemainingIdeal, dataRemainingTasks,
dataRemainingEfforts ],
+ {
+ axesDefaults: {
+ pad : 1
+ },
+ seriesColors: [ '#000', '#DDDDDD', '#00FA9A',
'#B22222' ],
+ legend: {
+ show: true,
+ location: 'ne',
+ xoffset: 12,
+ yoffset: 12
+ },
+ axes : {
+ xaxis : {
+ renderer :
jQuery.jqplot.DateAxisRenderer,
+ tickRenderer:
jQuery.jqplot.CanvasAxisTickRenderer,
+ tickOptions:{
+ angle: -90,
+ fontSize : '1.3em',
+ formatString : '%Y-%m-%d'
+ },
+ numberTicks: <?php echo
count($xaxisData) - 2; ?>,
+ min: <?php echo
$release->getStartDate() * 1000; ?>,
+ max: <?php echo $release->getEndDate()
* 1000; ?>
+ },
+ yaxis : {
+ autoscale:true,
+ min : 0,
+ label: "<?php echo _('Completed
tasks') ?>" ,
+ labelRenderer:
jQuery.jqplot.CanvasAxisLabelRenderer,
+ labelOptions:{
+ fontSize : '12px'
+ }
+ },
+ y2axis: {
+ autoscale:true,
+ min : 0,
+ tickOptions:{
+ isMinorTick: true,
+ formatString: "%.1f <?php echo _('m/d')
?>"
+ }
+ }
+ },
+ series:[
+ { show : false }, // to indicates all
dates only
+ { label : "<?php echo _('Ideal
burndown') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } },
+ { label : "<?php echo _('Remaining
tasks') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 },
yaxis: 'yaxis' },
+ { label : "<?php echo _('Remaining
efforts') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } ,
yaxis:'y2axis' }
+ ],
+ highlighter: {
+ show: true,
+ sizeAdjust: 8
+ },
+ cursor: {
+ show: false
+ }
+ }
+ );
+ });
+</script>
\ No newline at end of file
diff --git
a/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
b/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
new file mode 100644
index 0000000..5b8e358
--- /dev/null
+++ b/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
@@ -0,0 +1 @@
+alter table plugin_taskboard_releases_snapshots alter column
completed_man_days real;
diff --git a/src/plugins/taskboard/db/taskboard-init.sql
b/src/plugins/taskboard/db/taskboard-init.sql
index 86d1e4f..6ce142f 100644
--- a/src/plugins/taskboard/db/taskboard-init.sql
+++ b/src/plugins/taskboard/db/taskboard-init.sql
@@ -23,7 +23,7 @@ CREATE TABLE plugin_taskboard_trackers (
CREATE TABLE plugin_taskboard_columns (
taskboard_column_id SERIAL primary key,
- taskboard_id integer REFERENCES plugin_taskboard(taskboard_id) ON DELETE
CASCADE,
+ taskboard_id integer REFERENCES plugin_taskboard(taskboard_id) ON DELETE
CASCADE,
title text NOT NULL,
title_background_color text,
column_background_color text,
@@ -34,8 +34,8 @@ CREATE TABLE plugin_taskboard_columns (
CREATE TABLE plugin_taskboard_columns_resolutions (
taskboard_column_value_id SERIAL primary key,
- taskboard_column_id integer REFERENCES plugin_taskboard_columns(
taskboard_column_id ) ON DELETE CASCADE,
- taskboard_column_resolution text NOT NULL
+ taskboard_column_id integer REFERENCES plugin_taskboard_columns(
taskboard_column_id ) ON DELETE CASCADE,
+ taskboard_column_resolution text NOT NULL
);
-- ALTER TABLE plugin_taskboard_columns_resolutions OWNER TO gforge;
@@ -43,7 +43,7 @@ CREATE TABLE plugin_taskboard_columns_resolutions (
-- records with empty source is a records by default
-- possible set rules:
-- resolution = 'Fixed' (alias = element_name, for extra fields, having
elements)
--- remaining_estimated_cost = 0 (alias = value, for extra fields, using values
)
+-- remaining_estimated_cost = 0 (alias = value, for extra fields, using values
)
--
CREATE TABLE plugin_taskboard_columns_sources (
taskboard_column_source_id SERIAL primary key,
@@ -75,6 +75,6 @@ CREATE TABLE plugin_taskboard_releases_snapshots (
completed_story_points integer NOT NULL DEFAULT 0,
completed_man_days integer NOT NULL DEFAULT 0
);
-ALTER TABLE plugin_taskboard_releases_snapshots
- ADD CONSTRAINT plugin_taskboard_releases_snapshots_date
+ALTER TABLE plugin_taskboard_releases_snapshots
+ ADD CONSTRAINT plugin_taskboard_releases_snapshots_date
UNIQUE (taskboard_release_id, snapshot_date);
diff --git a/src/plugins/taskboard/www/index.php
b/src/plugins/taskboard/www/index.php
index 5482c33..bdf2fec 100644
--- a/src/plugins/taskboard/www/index.php
+++ b/src/plugins/taskboard/www/index.php
@@ -227,7 +227,9 @@ var gAjaxUrl = '<?php echo util_make_url
('/plugins/'.$pluginTaskboard->name.'/a
var gMessages = {
'notasks' : "<?php echo _('There are no tasks found.') ?>",
'progressByTasks' : "<?php echo _('Progress by tasks') ?>",
- 'progressByCost' : "<?php echo _('Progress by cost') ?>"
+ 'progressByCost' : "<?php echo _('Progress by cost') ?>",
+ 'remainingCost' : "<?php echo _('Remaining m/d') ?>",
+ 'completedCost' : "<?php echo _('Completed m/d') ?>"
};
<?php
diff --git a/src/plugins/taskboard/www/js/agile-board.js
b/src/plugins/taskboard/www/js/agile-board.js
index 9b16e81..dcaf08c 100644
--- a/src/plugins/taskboard/www/js/agile-board.js
+++ b/src/plugins/taskboard/www/js/agile-board.js
@@ -141,8 +141,11 @@ function drawBoardProgress() {
totalTasks ++;
if(
aUserStories[i].tasks[t].estimated_dev_effort ) {
- totalCostEstimated += parseInt(
aUserStories[i].tasks[t].estimated_dev_effort );
- totalCostRemaining += parseInt(
aUserStories[i].tasks[t].remaining_dev_effort );
+ totalCostEstimated +=
parseFloat( aUserStories[i].tasks[t].estimated_dev_effort );
+ }
+
+ if(
aUserStories[i].tasks[t].remaining_dev_effort ) {
+ totalCostRemaining +=
parseFloat( aUserStories[i].tasks[t].remaining_dev_effort );
}
lastPhaseWithTasks = j;
@@ -176,14 +179,14 @@ function drawBoardProgress() {
html += '</td></tr><table>';
- if( parseInt(totalCostEstimated) > 0 ) {
+ if( parseFloat(totalCostEstimated) > 0 ) {
var totalCostCompleted = totalCostEstimated -
totalCostRemaining;
var wt = parseInt( totalCostCompleted/totalCostEstimated * 100);
// show progress by cost
html += '<table>';
html += '<tr><td width="' + parseInt( 100 / aPhases.length ) +
'%" style="padding: 0;">' + gMessages.progressByCost + ':</td><td
style="padding: 0;">';
- html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;">' + totalCostCompleted + '</div>';
- html += '<div class="agile-board-progress-bar-remains"
style="width: ' + ( 100 - wt ) + '%;">' + totalCostRemaining + '</div>';
+ html += '<div class="agile-board-progress-bar-remains"
style="width: ' + ( 100 - wt ) + '%;" title="' + gMessages['remainingCost'] +
'">' + totalCostRemaining + '</div>';
+ html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;" title="' + gMessages['completedCost'] + '">' +
totalCostCompleted + '</div>';
html += '</td></tr><table>';
}
commit b16cafc79d7c2ca2fd0de39b3ab8dc9ccc54a6d2
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun Mar 15 17:17:32 2015 +0200
taskboard: cherry-pick 3054d9398e0ab6112e7150b100b02f7ab995a31b
diff --git a/src/plugins/taskboard/common/TaskBoardRelease.class.php
b/src/plugins/taskboard/common/TaskBoardRelease.class.php
index fdd8e41..a368859 100644
--- a/src/plugins/taskboard/common/TaskBoardRelease.class.php
+++ b/src/plugins/taskboard/common/TaskBoardRelease.class.php
@@ -254,7 +254,88 @@ class TaskBoardRelease extends Error {
* @return boolean success.
*/
function saveSnapshot($snapshot_datetime) {
- // TODO
+ $user_stories =
$this->Taskboard->getUserStories($this->getTitle());
+ $columns = $this->Taskboard->getColumns($this->getTitle());
+
+ $_columns_num = count($columns);
+ $_completed_user_stories = 0;
+ $_completed_tasks = 0;
+ $_completed_story_points = 0;
+ $_completed_man_days = 0;
+
+ foreach( $user_stories as $us ) {
+ $completed_us = true;
+
+ for($i=0; $i < $_columns_num ; $i++ ) {
+ foreach( $us['tasks'] as $tsk ) {
+ if( $tsk['phase_id'] ==
$columns[$i]->getID() ) {
+ if( $i + 1 == $_columns_num ) {
+ // last column, so-
completed task
+ $_completed_tasks++;
+ } else {
+ // incomplete task, so
incomplete US
+ $completed_us = false;
+ }
+ }
+ }
+
+ }
+
+ if( $completed_us ) {
+ $_completed_user_stories++;
+ // TODO $_completed_story_points += ...
+ }
+ }
+
+
+ $res = db_query_params(
+ 'SELECT taskboard_release_snapshot_id FROM
plugin_taskboard_releases_snapshots WHERE taskboard_release_id=$1 AND
snapshot_date=$2',
+ array ($this->getID(), $snapshot_datetime )
+ );
+
+ if (!$res) {
+ $this->setError('TaskBoardRelease: Cannot get release
snapshot');
+ return false;
+ }
+
+ $row = db_fetch_array($res);
+ db_free_result($res);
+
+ if( $row ) {
+ $res = db_query_params(
+ 'UPDATE
plugin_taskboard_releases_snapshots
+ SET completed_user_stories=$1,
completed_tasks=$2, completed_story_points=$3, completed_man_days=$4
+ WHERE taskboard_release_snapshot_id=$5',
+ array(
+
$_completed_user_stories,
+ $_completed_tasks,
+ 0, //TODO
+ 0, //TODO
+
intval($row['taskboard_release_snapshot_id'])
+ )
+ );
+ if (!$res) {
+ return false;
+ }
+ db_free_result($res);
+ } else {
+ $res = db_query_params(
+ 'INSERT INTO
plugin_taskboard_releases_snapshots(taskboard_release_id, snapshot_date,
completed_user_stories, completed_tasks, completed_story_points,
completed_man_days)
+ VALUES($1,$2,$3,$4,$5,$6)',
+ array(
+ $this->getID(),
+ $snapshot_datetime,
+
$_completed_user_stories,
+ $_completed_tasks,
+ 0, //TODO
+ 0 //TODO
+ )
+ );
+ if (!$res) {
+ return false;
+ }
+ db_free_result($res);
+ }
return true;
}
diff --git
a/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
b/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
index d6e5252..ee91a31 100644
--- a/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
+++ b/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
@@ -35,11 +35,12 @@ if( $release ) {
if( $snapshot_datetime ) {
if( $snapshot_datetime >= $release->getStartDate() &&
$snapshot_datetime <= $release->getEndDate() ) {
db_begin();
- if( !$release->saveSnapshot( $snapshot_datetime ) ) {
+ if( !$release->saveSnapshot( $snapshot_datetime,
$release_id ) ) {
$ret['alert'] = _('Cannot save release
snapshot');
db_rollback();
} else {
db_commit();
+ $ret['alert'] = sprintf( _('Snapshot is
succesfully saved for %s'), $snapshot_date);
}
} else {
$ret['alert'] = _('Snapshot date should be withing
release period');
diff --git a/src/plugins/taskboard/www/css/agile-board.css
b/src/plugins/taskboard/www/css/agile-board.css
index beb0d4b..d387c1b 100644
--- a/src/plugins/taskboard/www/css/agile-board.css
+++ b/src/plugins/taskboard/www/css/agile-board.css
@@ -122,8 +122,9 @@
}
#taskboard-release-description {
- margin:0 auto;
float: left;
+ font-size: 14px;
+ margin: 4px;
}
#taskboard-release-snapshot {
diff --git a/src/plugins/taskboard/www/index.php
b/src/plugins/taskboard/www/index.php
index 4b5edd8..5482c33 100644
--- a/src/plugins/taskboard/www/index.php
+++ b/src/plugins/taskboard/www/index.php
@@ -139,7 +139,7 @@ if ($taskboard->getReleaseField()) {
<?php echo _('Release')._(':
').$release_box; ?>
</td>
<?php if ( forge_check_perm('tracker_admin',
$group_id ) ) { ?>
- <td>
+ <td style="vertical-align: middle;">
<div
id="taskboard-release-description"></div>
<div id="taskboard-release-snapshot">
<input type="hidden"
name="taskboard_release_id" id="taskboard-release-id" value="" />
commit 283838b1ba70566e7ed4ce36215c7dbb9f061c95
Author: Vitaliy Pylypiv <[email protected]>
Date: Mon Mar 9 18:48:06 2015 +0200
taskboard: cherry-pick 9ff2b752ef363c990f454cb446b7e5e3541ade33
diff --git a/src/plugins/taskboard/etc/taskboard.ini
b/src/plugins/taskboard/etc/taskboard.ini
index 3a72ad5..0ee3181 100644
--- a/src/plugins/taskboard/etc/taskboard.ini
+++ b/src/plugins/taskboard/etc/taskboard.ini
@@ -1,4 +1,3 @@
[taskboard]
-
trackers_adapter_class = TaskBoardBasicAdapter
plugin_status = valid
commit a0a3bf0af69a78dc172bef6186ba9baa29119f2d
Author: Vitaliy Pylypiv <[email protected]>
Date: Sun Mar 15 09:49:12 2015 +0200
taskboard: cherry-pick d95cbf867bf90ee30bd2c07328d2478580bbda29: small
optimization
diff --git a/src/plugins/taskboard/www/index.php
b/src/plugins/taskboard/www/index.php
index 182f687..4b5edd8 100644
--- a/src/plugins/taskboard/www/index.php
+++ b/src/plugins/taskboard/www/index.php
@@ -191,8 +191,7 @@ if ($taskboard->getReleaseField()) {
<?php
$used_trackers = $taskboard->getUsedTrackersIds();
if(count($used_trackers) == 1) {
- $tracker =
$taskboard->TrackersAdapter->getTasksTracker($used_trackers[0]);
- echo html_e('input', array('type' => 'hidden', 'name'
=> 'tracker_id', 'id' => 'tracker_id', 'value' => $tracker->getID()));
+ echo html_e('input', array('type' => 'hidden', 'name'
=> 'tracker_id', 'id' => 'tracker_id', 'value' => $used_trackers[0]));
} else {
// select target tracker if more then single trackers
are configured
echo "<div>\n";
-----------------------------------------------------------------------
Summary of changes:
src/plugins/taskboard/TODO.txt | 6 +-
.../common/TaskBoardColumnSource.class.php | 15 +-
.../taskboard/common/TaskBoardRelease.class.php | 135 ++++++++++++++++-
.../common/actions/ajax_save_release_snapshot.php | 3 +-
.../adapters/TaskBoardBasicAdapter.class.php | 13 +-
.../taskboard/common/views/admin/edit_column.php | 1 -
.../taskboard/common/views/releases/burndown.php | 166 +++++++++++++++++++++
.../20150607-plugin-taskboard-integer-to-real.sql | 1 +
src/plugins/taskboard/db/taskboard-init.sql | 12 +-
src/plugins/taskboard/etc/taskboard.ini | 1 -
src/plugins/taskboard/www/css/agile-board.css | 3 +-
src/plugins/taskboard/www/index.php | 9 +-
src/plugins/taskboard/www/js/agile-board.js | 15 +-
13 files changed, 354 insertions(+), 26 deletions(-)
create mode 100644 src/plugins/taskboard/common/views/releases/burndown.php
create mode 100644
src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
diff --git a/src/plugins/taskboard/TODO.txt b/src/plugins/taskboard/TODO.txt
index 9a6048e..7a26292 100644
--- a/src/plugins/taskboard/TODO.txt
+++ b/src/plugins/taskboard/TODO.txt
@@ -10,14 +10,14 @@
- DONE View - filter by assigned persons
- DONE Releases are based either on US or on tasks
- DONE View - indicators - progress by tasks number
-- API - configured fields support in mapped tasks ('estimated_dev_effort',
'remaining_dev_effort', 'user_story' )
-- View - indicators - progress by tasks cost (if efforts fields are configured)
+- DONE API - configured fields support in mapped tasks
('estimated_dev_effort', 'remaining_dev_effort', 'user_story' )
+- DONE View - indicators - progress by tasks cost (if efforts fields are
configured)
- DONE Admin - releases management
- View - auto ref rate support
- Admin - auto ref rate support
- Admin - adapters - coloring support
- View - adapters - coloring support (for GT)
- View - colors by extrafield (for GT)
-- View - indicators - burndown chart
+- DONE View - indicators - burndown chart
- View - indicators - velocity calculation
- Improve taskboard initialization - columns by default?
diff --git a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
index feae4ba..4686189 100644
--- a/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
+++ b/src/plugins/taskboard/common/TaskBoardColumnSource.class.php
@@ -248,8 +248,21 @@ class TaskBoardColumnSource extends Error {
if( $this->getAutoassign() ) {
$assigned_to = user_getid();
}
+
- $msg = $this->getTaskboard()->TrackersAdapter->updateTask(
$task,$assigned_to, $this->getTargetResolution() );
+ $remaining_cost = NULL;
+ if( $this->getTaskboard()->getRemainingCostField() ) {
+ // set 0 to remainin cost if target column is a last one
+ $target_column = taskboard_column_get_object(
$this->getTargetColumnID() );
+
+ $columns = $this->getTaskboard()->getColumns();
+ if( $target_column->getOrder() == count($columns) ) {
+ // final column, so set remaining cost to 0
+ $remaining_cost = 0;
+ }
+ }
+
+ $msg = $this->getTaskboard()->TrackersAdapter->updateTask(
$task, $assigned_to, $this->getTargetResolution(), NULL, NULL, $remaining_cost
);
if($msg) {
$msg = _('Tracker error')._(': ').$msg;
}
diff --git a/src/plugins/taskboard/common/TaskBoardRelease.class.php
b/src/plugins/taskboard/common/TaskBoardRelease.class.php
index fdd8e41..03d65de 100644
--- a/src/plugins/taskboard/common/TaskBoardRelease.class.php
+++ b/src/plugins/taskboard/common/TaskBoardRelease.class.php
@@ -247,6 +247,63 @@ class TaskBoardRelease extends Error {
}
/**
+ * Get release volume - number of total
+ *
+ * @return array hash with user_stories, tasks, story_points,
man_days key
+ */
+ function getVolume() {
+ $user_stories =
$this->Taskboard->getUserStories($this->getTitle());
+ $columns = $this->Taskboard->getColumns($this->getTitle());
+
+ $_columns_num = count($columns);
+ $ret = array(
+ 'user_stories' => 0,
+ 'completed_user_stories' => 0,
+ 'tasks' => 0,
+ 'completed_tasks' => 0,
+ 'story_points' => 0,
+ 'completed_story_points' => 0,
+ 'man_days'=> 0,
+ 'completed_man_days'=> 0,
+ );
+
+ foreach( $user_stories as $us ) {
+ $completed_us = true;
+
+ for($i=0; $i < $_columns_num ; $i++ ) {
+ foreach( $us['tasks'] as $tsk ) {
+ if( $tsk['phase_id'] ==
$columns[$i]->getID() ) {
+ if( $i + 1 == $_columns_num ) {
+ // last column, so -
completed task
+
$ret['completed_tasks']++;
+ } else {
+ // incomplete task, so
incomplete US
+ $completed_us = false;
+ }
+ $ret['tasks']++;
+
+ if(
$tsk['estimated_dev_effort'] ) {
+
$ret['completed_man_days'] += ( (float) $tsk['estimated_dev_effort'] - (float)
$tsk['remaining_dev_effort'] );
+ }
+
+ if(
$tsk['estimated_dev_effort'] ) {
+ $ret['man_days'] +=
(float) $tsk['estimated_dev_effort'];
+ }
+ }
+ }
+ }
+
+ if( $completed_us ) {
+ $ret['completed_user_stories']++;
+ // TODO $_completed_story_points += ...
+ }
+ $ret['user_stories']++;
+ }
+
+ return $ret;
+ }
+
+ /**
* Save current taskboard snapshot. So, we can have a history of
release implementation,
* that could be used for different indicators calculation.
*
@@ -254,8 +311,84 @@ class TaskBoardRelease extends Error {
* @return boolean success.
*/
function saveSnapshot($snapshot_datetime) {
- // TODO
+ $release_volume = $this->getVolume();
+
+ $res = db_query_params(
+ 'SELECT taskboard_release_snapshot_id FROM
plugin_taskboard_releases_snapshots WHERE taskboard_release_id=$1 AND
snapshot_date=$2',
+ array ($this->getID(), $snapshot_datetime )
+ );
+
+ if (!$res) {
+ $this->setError('TaskBoardRelease: Cannot get release
snapshot');
+ return false;
+ }
+
+ $row = db_fetch_array($res);
+ db_free_result($res);
+
+ if( $row ) {
+ $res = db_query_params(
+ 'UPDATE
plugin_taskboard_releases_snapshots
+ SET completed_user_stories=$1,
completed_tasks=$2, completed_story_points=$3, completed_man_days=$4
+ WHERE taskboard_release_snapshot_id=$5',
+ array(
+
$release_volume['completed_user_stories'],
+
$release_volume['completed_tasks'],
+
$release_volume['completed_story_points'],
+
$release_volume['completed_man_days'],
+
intval($row['taskboard_release_snapshot_id'])
+ )
+ );
+ if (!$res) {
+ return false;
+ }
+ db_free_result($res);
+ } else {
+ $res = db_query_params(
+ 'INSERT INTO
plugin_taskboard_releases_snapshots(taskboard_release_id, snapshot_date,
completed_user_stories, completed_tasks, completed_story_points,
completed_man_days)
+ VALUES($1,$2,$3,$4,$5,$6)',
+ array(
+ $this->getID(),
+ $snapshot_datetime,
+
$release_volume['completed_user_stories'],
+
$release_volume['completed_tasks'],
+
$release_volume['completed_story_points'],
+
$release_volume['completed_man_days'],
+ )
+ );
+ if (!$res) {
+ return false;
+ }
+ db_free_result($res);
+ }
return true;
}
+
+ /**
+ * Get current release snapshots
+ *
+ * @return array
+ */
+ function getSnapshots() {
+ $ret = array();
+
+ $res = db_query_params(
+ 'SELECT snapshot_date, completed_user_stories,
completed_tasks, completed_story_points, completed_man_days
+ FROM plugin_taskboard_releases_snapshots WHERE
taskboard_release_id=$1 ORDER BY snapshot_date',
+ array ($this->getID() )
+ );
+
+ if (!$res) {
+ $this->setError('TaskBoardRelease: Cannot get release
snapshots');
+ return false;
+ }
+
+ while( $row = db_fetch_array($res) ) {
+ $ret[] = $row;
+ }
+ db_free_result($res);
+
+ return $ret;
+ }
}
diff --git
a/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
b/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
index d6e5252..ee91a31 100644
--- a/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
+++ b/src/plugins/taskboard/common/actions/ajax_save_release_snapshot.php
@@ -35,11 +35,12 @@ if( $release ) {
if( $snapshot_datetime ) {
if( $snapshot_datetime >= $release->getStartDate() &&
$snapshot_datetime <= $release->getEndDate() ) {
db_begin();
- if( !$release->saveSnapshot( $snapshot_datetime ) ) {
+ if( !$release->saveSnapshot( $snapshot_datetime,
$release_id ) ) {
$ret['alert'] = _('Cannot save release
snapshot');
db_rollback();
} else {
db_commit();
+ $ret['alert'] = sprintf( _('Snapshot is
succesfully saved for %s'), $snapshot_date);
}
} else {
$ret['alert'] = _('Snapshot date should be withing
release period');
diff --git
a/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
b/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
index f6283c9..17a723f 100644
--- a/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
+++ b/src/plugins/taskboard/common/adapters/TaskBoardBasicAdapter.class.php
@@ -322,7 +322,7 @@ class TaskBoardBasicAdapter {
*
* @return string error message in case of fail
*/
- function updateTask(&$artifact, $assigned_to, $resolution, $title =
NULL, $description = NULL) {
+ function updateTask(&$artifact, $assigned_to, $resolution, $title =
NULL, $description = NULL, $remaining_cost=NULL ) {
if (!$assigned_to) {
$assigned_to = $artifact->getAssignedTo();
}
@@ -341,6 +341,17 @@ class TaskBoardBasicAdapter {
}
}
+ if($remaining_cost!==NULL) {
+ $remaining_cost_alias =
$this->TaskBoard->getRemainingCostField();
+
+ if($remaining_cost_alias) {
+ if (array_key_exists($remaining_cost_alias,
$fields_ids)){
+ $remaining_cost_field_id =
$fields_ids[$remaining_cost_alias];
+ $extra_fields[ $remaining_cost_field_id
] = $remaining_cost;
+ }
+ }
+ }
+
if (!$title) {
$title =
htmlspecialchars_decode($artifact->getSummary());
}
diff --git a/src/plugins/taskboard/common/views/admin/edit_column.php
b/src/plugins/taskboard/common/views/admin/edit_column.php
index 480dfa0..2f89bb2 100644
--- a/src/plugins/taskboard/common/views/admin/edit_column.php
+++ b/src/plugins/taskboard/common/views/admin/edit_column.php
@@ -94,7 +94,6 @@ if ($column_id) {
echo $HTML->multiTableRow(array(), $cells);
$cells = array();
$cells[][] = html_e('strong', array(), _('Alert message'));
- error_log($drop_rules_by_default->getAlertText());
$cells[][] = html_e('textarea', array('name' => 'alert', 'cols'
=> 79, 'rows' => 5), htmlspecialchars($drop_rules_by_default->getAlertText()),
false);
echo $HTML->multiTableRow(array(), $cells);
echo $HTML->listTableBottom();
diff --git a/src/plugins/taskboard/common/views/releases/burndown.php
b/src/plugins/taskboard/common/views/releases/burndown.php
new file mode 100644
index 0000000..3e241c6
--- /dev/null
+++ b/src/plugins/taskboard/common/views/releases/burndown.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * Copyright (C) 2015 Vitaliy Pylypiv <[email protected]>
+ *
+ * This file is part of FusionForge.
+ *
+ * FusionForge 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.
+ *
+ * FusionForge 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+global $group_id, $group, $taskboard;
+
+$release_id = getIntFromRequest('release_id', NULL);
+
+$release = new TaskBoardRelease( $taskboard, $release_id );
+
+html_use_jqueryjqplotpluginCanvas();
+html_use_jqueryjqplotplugindateAxisRenderer();
+html_use_jqueryjqplotpluginhighlighter();
+
+$taskboard->header(
+ array(
+ 'title' => _('Taskboard for
').$group->getPublicName()._(': '). _('Releases')._(': ')._('Burndown
chart')._(': ').$release->getTitle() ,
+ 'pagename' => _('Releases')._(': ')._('Burndown
chart')._(': ').$release->getTitle(),
+ 'sectionvals' => array($group->getPublicName()),
+ 'group' => $group_id
+ )
+ );
+
+if ($taskboard->isError()) {
+ echo $HTML->error_msg($taskboard->getErrorMessage());
+} else {
+ echo html_e('div', array('id' => 'messages', 'style' => 'display:
none;'), '', false);
+}
+
+// $xaxisData is used to have an every date on the X axis
+$xaxisData = array();
+$chartDate = $release->getStartDate();
+while( $chartDate <= $release->getEndDate() ) {
+ $xaxisData[] = array( date( 'r', $chartDate) , 0);
+ $chartDate += 86400;
+}
+
+$release_volume = $release->getVolume();
+
+// ideal burndown
+$dataIdeal = array(
+ array( $release->getStartDate() * 1000, $release_volume['tasks']),
+ array( $release->getEndDate() * 1000, 0)
+);
+
+$release_snapshots = $release->getSnapshots();
+$dataRemainingTasks = array();
+$dataRemainingEfforts = array();
+
+foreach( $release_snapshots as $snapshot ) {
+ if( count($dataRemainingTasks) == 0 && $snapshot['snapshot_date'] !=
$release->getStartDate() ) {
+ // initialize start point if snapshot is missing for the first
day
+ $dataRemainingTasks[] = array( $release->getStartDate() * 1000,
$release_volume['tasks'] );
+ $dataRemainingEfforts[] = array( $release->getStartDate() *
1000, $release_volume['man_days'] );
+ }
+
+ $dataRemainingTasks[] = array( $snapshot['snapshot_date'] * 1000, (
$release_volume['tasks'] - $snapshot['completed_tasks'] ) );
+ $dataRemainingEfforts[] = array( $snapshot['snapshot_date'] * 1000, (
$release_volume['man_days'] - $snapshot['completed_man_days'] ) );
+}
+
+
+
+?>
+<div id="taskboard-burndown-chart-nav">
+ <button id="taskboard-view-btn"><?php echo _('Taskboard'); ?></button>
+ <br/>
+</div>
+
+<figure>
+ <figcaption><?php echo _("Burndown chart") . ' : ' .
$release->getTitle() ?></figcaption>
+ <div id="taskboard-burndown-chart">
+ </div>
+</figure>
+
+<script>
+ var burndownChart;
+ var xaxisData = <?php echo json_encode( $xaxisData ); ?>;
+ var dataRemainingTasks = <?php echo json_encode( $dataRemainingTasks );
?>;
+ var dataRemainingEfforts = <?php echo json_encode(
$dataRemainingEfforts ); ?>;
+ var dataRemainingIdeal = <?php echo json_encode( $dataIdeal ); ?>;
+
+ jQuery( document ).ready(function( $ ) {
+ jQuery('#taskboard-view-btn').click( function ( e ) {
+ window.location = '<?php echo util_make_url
('/plugins/'.$pluginTaskboard->name.'?group_id='. $group_id . '&_release=' .
$release_id ); ?>';
+ e.preventDefault();
+ });
+
+ burndownChart = jQuery.jqplot(
+ 'taskboard-burndown-chart',
+ [ xaxisData, dataRemainingIdeal, dataRemainingTasks,
dataRemainingEfforts ],
+ {
+ axesDefaults: {
+ pad : 1
+ },
+ seriesColors: [ '#000', '#DDDDDD', '#00FA9A',
'#B22222' ],
+ legend: {
+ show: true,
+ location: 'ne',
+ xoffset: 12,
+ yoffset: 12
+ },
+ axes : {
+ xaxis : {
+ renderer :
jQuery.jqplot.DateAxisRenderer,
+ tickRenderer:
jQuery.jqplot.CanvasAxisTickRenderer,
+ tickOptions:{
+ angle: -90,
+ fontSize : '1.3em',
+ formatString :
'%Y-%m-%d'
+ },
+ numberTicks: <?php echo
count($xaxisData) - 2; ?>,
+ min: <?php echo
$release->getStartDate() * 1000; ?>,
+ max: <?php echo
$release->getEndDate() * 1000; ?>
+ },
+ yaxis : {
+ autoscale:true,
+ min : 0,
+ label: "<?php echo _('Completed
tasks') ?>" ,
+ labelRenderer:
jQuery.jqplot.CanvasAxisLabelRenderer,
+ labelOptions:{
+ fontSize : '12px'
+ }
+ },
+ y2axis: {
+ autoscale:true,
+ min : 0,
+ tickOptions:{
+ isMinorTick: true,
+ formatString: "%.1f <?php echo
_('m/d') ?>"
+ }
+ }
+ },
+ series:[
+ { show : false }, // to indicate all
dates
+ { label : "<?php echo _('Ideal
burndown') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } },
+ { label : "<?php echo _('Remaining
tasks') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 },
yaxis: 'yaxis' },
+ { label : "<?php echo _('Remaining
efforts') ;?>", lineWidth:1, markerOptions : { style : 'circle', size : 5 } ,
yaxis:'y2axis' }
+ ],
+ highlighter: {
+ show: true,
+ sizeAdjust: 8
+ },
+ cursor: {
+ show: false
+ }
+ }
+ );
+ });
+</script>
\ No newline at end of file
diff --git
a/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
b/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
new file mode 100644
index 0000000..5b8e358
--- /dev/null
+++ b/src/plugins/taskboard/db/20150607-plugin-taskboard-integer-to-real.sql
@@ -0,0 +1 @@
+alter table plugin_taskboard_releases_snapshots alter column
completed_man_days real;
diff --git a/src/plugins/taskboard/db/taskboard-init.sql
b/src/plugins/taskboard/db/taskboard-init.sql
index 86d1e4f..6ce142f 100644
--- a/src/plugins/taskboard/db/taskboard-init.sql
+++ b/src/plugins/taskboard/db/taskboard-init.sql
@@ -23,7 +23,7 @@ CREATE TABLE plugin_taskboard_trackers (
CREATE TABLE plugin_taskboard_columns (
taskboard_column_id SERIAL primary key,
- taskboard_id integer REFERENCES plugin_taskboard(taskboard_id) ON DELETE
CASCADE,
+ taskboard_id integer REFERENCES plugin_taskboard(taskboard_id) ON DELETE
CASCADE,
title text NOT NULL,
title_background_color text,
column_background_color text,
@@ -34,8 +34,8 @@ CREATE TABLE plugin_taskboard_columns (
CREATE TABLE plugin_taskboard_columns_resolutions (
taskboard_column_value_id SERIAL primary key,
- taskboard_column_id integer REFERENCES plugin_taskboard_columns(
taskboard_column_id ) ON DELETE CASCADE,
- taskboard_column_resolution text NOT NULL
+ taskboard_column_id integer REFERENCES plugin_taskboard_columns(
taskboard_column_id ) ON DELETE CASCADE,
+ taskboard_column_resolution text NOT NULL
);
-- ALTER TABLE plugin_taskboard_columns_resolutions OWNER TO gforge;
@@ -43,7 +43,7 @@ CREATE TABLE plugin_taskboard_columns_resolutions (
-- records with empty source is a records by default
-- possible set rules:
-- resolution = 'Fixed' (alias = element_name, for extra fields, having
elements)
--- remaining_estimated_cost = 0 (alias = value, for extra fields, using values
)
+-- remaining_estimated_cost = 0 (alias = value, for extra fields, using values
)
--
CREATE TABLE plugin_taskboard_columns_sources (
taskboard_column_source_id SERIAL primary key,
@@ -75,6 +75,6 @@ CREATE TABLE plugin_taskboard_releases_snapshots (
completed_story_points integer NOT NULL DEFAULT 0,
completed_man_days integer NOT NULL DEFAULT 0
);
-ALTER TABLE plugin_taskboard_releases_snapshots
- ADD CONSTRAINT plugin_taskboard_releases_snapshots_date
+ALTER TABLE plugin_taskboard_releases_snapshots
+ ADD CONSTRAINT plugin_taskboard_releases_snapshots_date
UNIQUE (taskboard_release_id, snapshot_date);
diff --git a/src/plugins/taskboard/etc/taskboard.ini
b/src/plugins/taskboard/etc/taskboard.ini
index 3a72ad5..0ee3181 100644
--- a/src/plugins/taskboard/etc/taskboard.ini
+++ b/src/plugins/taskboard/etc/taskboard.ini
@@ -1,4 +1,3 @@
[taskboard]
-
trackers_adapter_class = TaskBoardBasicAdapter
plugin_status = valid
diff --git a/src/plugins/taskboard/www/css/agile-board.css
b/src/plugins/taskboard/www/css/agile-board.css
index beb0d4b..d387c1b 100644
--- a/src/plugins/taskboard/www/css/agile-board.css
+++ b/src/plugins/taskboard/www/css/agile-board.css
@@ -122,8 +122,9 @@
}
#taskboard-release-description {
- margin:0 auto;
float: left;
+ font-size: 14px;
+ margin: 4px;
}
#taskboard-release-snapshot {
diff --git a/src/plugins/taskboard/www/index.php
b/src/plugins/taskboard/www/index.php
index 182f687..bdf2fec 100644
--- a/src/plugins/taskboard/www/index.php
+++ b/src/plugins/taskboard/www/index.php
@@ -139,7 +139,7 @@ if ($taskboard->getReleaseField()) {
<?php echo _('Release')._(':
').$release_box; ?>
</td>
<?php if ( forge_check_perm('tracker_admin',
$group_id ) ) { ?>
- <td>
+ <td style="vertical-align: middle;">
<div
id="taskboard-release-description"></div>
<div id="taskboard-release-snapshot">
<input type="hidden"
name="taskboard_release_id" id="taskboard-release-id" value="" />
@@ -191,8 +191,7 @@ if ($taskboard->getReleaseField()) {
<?php
$used_trackers = $taskboard->getUsedTrackersIds();
if(count($used_trackers) == 1) {
- $tracker =
$taskboard->TrackersAdapter->getTasksTracker($used_trackers[0]);
- echo html_e('input', array('type' => 'hidden', 'name'
=> 'tracker_id', 'id' => 'tracker_id', 'value' => $tracker->getID()));
+ echo html_e('input', array('type' => 'hidden', 'name'
=> 'tracker_id', 'id' => 'tracker_id', 'value' => $used_trackers[0]));
} else {
// select target tracker if more then single trackers
are configured
echo "<div>\n";
@@ -228,7 +227,9 @@ var gAjaxUrl = '<?php echo util_make_url
('/plugins/'.$pluginTaskboard->name.'/a
var gMessages = {
'notasks' : "<?php echo _('There are no tasks found.') ?>",
'progressByTasks' : "<?php echo _('Progress by tasks') ?>",
- 'progressByCost' : "<?php echo _('Progress by cost') ?>"
+ 'progressByCost' : "<?php echo _('Progress by cost') ?>",
+ 'remainingCost' : "<?php echo _('Remaining m/d') ?>",
+ 'completedCost' : "<?php echo _('Completed m/d') ?>"
};
<?php
diff --git a/src/plugins/taskboard/www/js/agile-board.js
b/src/plugins/taskboard/www/js/agile-board.js
index 9b16e81..d55b7fc 100644
--- a/src/plugins/taskboard/www/js/agile-board.js
+++ b/src/plugins/taskboard/www/js/agile-board.js
@@ -141,8 +141,11 @@ function drawBoardProgress() {
totalTasks ++;
if(
aUserStories[i].tasks[t].estimated_dev_effort ) {
- totalCostEstimated += parseInt(
aUserStories[i].tasks[t].estimated_dev_effort );
- totalCostRemaining += parseInt(
aUserStories[i].tasks[t].remaining_dev_effort );
+ totalCostEstimated +=
parseFloat( aUserStories[i].tasks[t].estimated_dev_effort );
+ }
+
+ if(
aUserStories[i].tasks[t].remaining_dev_effort ) {
+ totalCostRemaining +=
parseFloat( aUserStories[i].tasks[t].remaining_dev_effort );
}
lastPhaseWithTasks = j;
@@ -176,14 +179,14 @@ function drawBoardProgress() {
html += '</td></tr><table>';
- if( parseInt(totalCostEstimated) > 0 ) {
+ if( parseFloat(totalCostEstimated) > 0 ) {
var totalCostCompleted = totalCostEstimated -
totalCostRemaining;
var wt = parseInt( totalCostCompleted/totalCostEstimated * 100);
// show progress by cost
html += '<table>';
html += '<tr><td width="' + parseInt( 100 / aPhases.length ) +
'%" style="padding: 0;">' + gMessages.progressByCost + ':</td><td
style="padding: 0;">';
- html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;">' + totalCostCompleted + '</div>';
- html += '<div class="agile-board-progress-bar-remains"
style="width: ' + ( 100 - wt ) + '%;">' + totalCostRemaining + '</div>';
+ html += '<div class="agile-board-progress-bar-done"
style="width: ' + wt + '%;" title="' + gMessages['completedCost'] + '">' +
totalCostCompleted + '</div>';
+ html += '<div class="agile-board-progress-bar-remains"
style="width: ' + ( 100 - wt ) + '%;" title="' + gMessages['remainingCost'] +
'">' + totalCostRemaining + '</div>';
html += '</td></tr><table>';
}
@@ -479,7 +482,7 @@ function initEditable() {
}
});
}
- });
+ });
}
hooks/post-receive
--
FusionForge
_______________________________________________
Fusionforge-commits mailing list
[email protected]
http://lists.fusionforge.org/cgi-bin/mailman/listinfo/fusionforge-commits