Add new analytic component "Estimated vs actual time per column"
This commit is contained in:
committed by
GitHub
parent
6cadf82a63
commit
a267aa368b
49
app/Analytic/EstimatedActualColumnAnalytic.php
Normal file
49
app/Analytic/EstimatedActualColumnAnalytic.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Analytic;
|
||||
|
||||
use Kanboard\Core\Base;
|
||||
use Kanboard\Model\TaskModel;
|
||||
|
||||
/**
|
||||
* Estimated vs actual time per column
|
||||
*
|
||||
* @package analytic
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class EstimatedActualColumnAnalytic extends Base
|
||||
{
|
||||
/**
|
||||
* Build report
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @return array
|
||||
*/
|
||||
public function build($project_id)
|
||||
{
|
||||
$rows = $this->db->table(TaskModel::TABLE)
|
||||
->columns('SUM(time_estimated) AS hours_estimated', 'SUM(time_spent) AS hours_spent', 'column_id')
|
||||
->eq('project_id', $project_id)
|
||||
->groupBy('column_id')
|
||||
->findAll();
|
||||
|
||||
$columns = $this->columnModel->getList($project_id);
|
||||
|
||||
$metrics = [];
|
||||
foreach ($columns as $column_id => $column_title) {
|
||||
$metrics[$column_id] = array(
|
||||
'hours_spent' => 0,
|
||||
'hours_estimated' => 0,
|
||||
'title' => $column_title,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$metrics[$row['column_id']]['hours_spent'] = (float) $row['hours_spent'];
|
||||
$metrics[$row['column_id']]['hours_estimated'] = (float) $row['hours_estimated'];
|
||||
}
|
||||
|
||||
return $metrics;
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,22 @@ class AnalyticController extends BaseController
|
||||
$this->commonAggregateMetrics('analytic/burndown', 'score', t('Burndown chart'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimated vs actual time per column
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function estimatedVsActualByColumn()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
$this->response->html($this->helper->layout->analytic('analytic/estimated_actual_column', array(
|
||||
'project' => $project,
|
||||
'metrics' => $this->estimatedActualColumnAnalytic->build($project['id']),
|
||||
'title' => t('Estimated vs actual time per column'),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Common method for CFD and Burdown chart
|
||||
*
|
||||
|
||||
@@ -15,6 +15,7 @@ use Pimple\Container;
|
||||
* @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
|
||||
* @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
|
||||
* @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
|
||||
* @property \Kanboard\Analytic\EstimatedActualColumnAnalytic $estimatedActualColumnAnalytic
|
||||
* @property \Kanboard\Core\Action\ActionManager $actionManager
|
||||
* @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
|
||||
* @property \Kanboard\Core\ExternalTask\ExternalTaskManager $externalTaskManager
|
||||
|
||||
@@ -77,6 +77,18 @@ class DateHelper extends Base
|
||||
return $dtF->diff($dtT)->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration in hours into human format
|
||||
*
|
||||
* @access public
|
||||
* @param float $hours
|
||||
* @return string
|
||||
*/
|
||||
public function durationHours($hours)
|
||||
{
|
||||
return sprintf('%0.2f %s', round($hours, 2), t('hours'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the age of an item in quasi human readable format.
|
||||
* It's in this format: <1h , NNh, NNd
|
||||
|
||||
@@ -24,6 +24,7 @@ class ClassProvider implements ServiceProviderInterface
|
||||
'EstimatedTimeComparisonAnalytic',
|
||||
'AverageLeadCycleTimeAnalytic',
|
||||
'AverageTimeSpentColumnAnalytic',
|
||||
'EstimatedActualColumnAnalytic',
|
||||
),
|
||||
'Model' => array(
|
||||
'ActionModel',
|
||||
|
||||
30
app/Template/analytic/estimated_actual_column.php
Normal file
30
app/Template/analytic/estimated_actual_column.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php if (! $is_ajax): ?>
|
||||
<div class="page-header">
|
||||
<h2><?= t('Estimated vs actual time per column') ?></h2>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (empty($metrics)): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?php else: ?>
|
||||
<?= $this->app->component('chart-project-estimated-actual-column', array(
|
||||
'metrics' => $metrics,
|
||||
'labelSpent' => t('Hours Spent'),
|
||||
'labelEstimated' => t('Hours Estimated'),
|
||||
)) ?>
|
||||
|
||||
<table class="table-striped">
|
||||
<tr>
|
||||
<th><?= t('Column') ?></th>
|
||||
<th><?= t('Hours Spent') ?></th>
|
||||
<th><?= t('Hours Estimated') ?></th>
|
||||
</tr>
|
||||
<?php foreach ($metrics as $column): ?>
|
||||
<tr>
|
||||
<td><?= $this->text->e($column['title']) ?></td>
|
||||
<td><?= $this->dt->durationHours($column['hours_spent']) ?></td>
|
||||
<td><?= $this->dt->durationHours($column['hours_estimated']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
@@ -21,6 +21,9 @@
|
||||
<li <?= $this->app->checkMenuSelection('AnalyticController', 'timeComparison') ?>>
|
||||
<?= $this->modal->replaceLink(t('Estimated vs actual time'), 'AnalyticController', 'timeComparison', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->checkMenuSelection('AnalyticController', 'estimatedVsActualByColumn') ?>>
|
||||
<?= $this->modal->replaceLink(t('Estimated vs actual time per column'), 'AnalyticController', 'estimatedVsActualByColumn', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
|
||||
<?= $this->hook->render('template:analytic:sidebar', array('project' => $project)) ?>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user