Add burndown chart
This commit is contained in:
@@ -125,4 +125,46 @@ class Analytic extends Base
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show burndown chart
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function burndown()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$values = $this->request->getValues();
|
||||
|
||||
$from = $this->request->getStringParam('from', date('Y-m-d', strtotime('-1week')));
|
||||
$to = $this->request->getStringParam('to', date('Y-m-d'));
|
||||
|
||||
if (! empty($values)) {
|
||||
$from = $values['from'];
|
||||
$to = $values['to'];
|
||||
}
|
||||
|
||||
if ($this->request->isAjax()) {
|
||||
$this->response->json(array(
|
||||
'metrics' => $this->projectDailySummary->getRawMetricsByDay($project['id'], $from, $to),
|
||||
'labels' => array(
|
||||
'day' => t('Date'),
|
||||
'score' => t('Complexity'),
|
||||
)
|
||||
));
|
||||
}
|
||||
else {
|
||||
$this->response->html($this->layout('analytic/burndown', array(
|
||||
'values' => array(
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
),
|
||||
'display_graph' => $this->projectDailySummary->countDays($project['id'], $from, $to) >= 2,
|
||||
'project' => $project,
|
||||
'date_format' => $this->config->get('application_date_format'),
|
||||
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||
'title' => t('Burndown chart for "%s"', $project['name']),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -852,4 +852,7 @@ return array(
|
||||
'uploaded by: %s' => 'Télécharger par : %s',
|
||||
'uploaded on: %s' => 'Télécharger le : %s',
|
||||
'size: %s' => 'Taille : %s',
|
||||
'Burndown chart for "%s"' => 'Graphique d\'avancement pour « %s »',
|
||||
'Burndown chart' => 'Graphique d\'avancement',
|
||||
'This chart show the task complexity over the time (Work Remaining).' => 'Ce graphique représente la complexité des tâches en fonction du temps (travail restant).',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -850,4 +850,7 @@ return array(
|
||||
// 'uploaded by: %s' => '',
|
||||
// 'uploaded on: %s' => '',
|
||||
// 'size: %s' => '',
|
||||
// 'Burndown chart for "%s"' => '',
|
||||
// 'Burndown chart' => '',
|
||||
// 'This chart show the task complexity over the time (Work Remaining).' => '',
|
||||
);
|
||||
|
||||
@@ -83,6 +83,8 @@ class ProjectAnalytic extends Base
|
||||
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
||||
}
|
||||
|
||||
ksort($metrics);
|
||||
|
||||
return array_values($metrics);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ class ProjectDailySummary extends Base
|
||||
/**
|
||||
* Update daily totals for the project
|
||||
*
|
||||
* "total" is the number open of tasks in the column
|
||||
* "score" is the sum of tasks score in the column
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param string $date Record date (YYYY-MM-DD)
|
||||
@@ -40,6 +43,7 @@ class ProjectDailySummary extends Base
|
||||
'project_id' => $project_id,
|
||||
'column_id' => $column_id,
|
||||
'total' => 0,
|
||||
'score' => 0,
|
||||
));
|
||||
|
||||
$db->table(ProjectDailySummary::TABLE)
|
||||
@@ -47,6 +51,11 @@ class ProjectDailySummary extends Base
|
||||
->eq('column_id', $column_id)
|
||||
->eq('day', $date)
|
||||
->update(array(
|
||||
'score' => $db->table(Task::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('column_id', $column_id)
|
||||
->eq('is_active', Task::STATUS_OPEN)
|
||||
->sum('score'),
|
||||
'total' => $db->table(Task::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq('column_id', $column_id)
|
||||
@@ -92,12 +101,39 @@ class ProjectDailySummary extends Base
|
||||
ProjectDailySummary::TABLE.'.column_id',
|
||||
ProjectDailySummary::TABLE.'.day',
|
||||
ProjectDailySummary::TABLE.'.total',
|
||||
ProjectDailySummary::TABLE.'.score',
|
||||
Board::TABLE.'.title AS column_title'
|
||||
)
|
||||
->join(Board::TABLE, 'id', 'column_id')
|
||||
->eq(ProjectDailySummary::TABLE.'.project_id', $project_id)
|
||||
->gte('day', $from)
|
||||
->lte('day', $to)
|
||||
->asc(ProjectDailySummary::TABLE.'.day')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw metrics for the project within a data range grouped by day
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param string $from Start date (ISO format YYYY-MM-DD)
|
||||
* @param string $to End date
|
||||
* @return array
|
||||
*/
|
||||
public function getRawMetricsByDay($project_id, $from, $to)
|
||||
{
|
||||
return $this->db->table(ProjectDailySummary::TABLE)
|
||||
->columns(
|
||||
ProjectDailySummary::TABLE.'.day',
|
||||
'SUM('.ProjectDailySummary::TABLE.'.total) AS total',
|
||||
'SUM('.ProjectDailySummary::TABLE.'.score) AS score'
|
||||
)
|
||||
->eq(ProjectDailySummary::TABLE.'.project_id', $project_id)
|
||||
->gte('day', $from)
|
||||
->lte('day', $to)
|
||||
->asc(ProjectDailySummary::TABLE.'.day')
|
||||
->groupBy(ProjectDailySummary::TABLE.'.day')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,12 @@ use PDO;
|
||||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 63;
|
||||
const VERSION = 64;
|
||||
|
||||
function version_64($pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE project_daily_summaries ADD COLUMN score INT NOT NULL DEFAULT 0');
|
||||
}
|
||||
|
||||
function version_63($pdo)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,12 @@ use PDO;
|
||||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 44;
|
||||
const VERSION = 45;
|
||||
|
||||
function version_45($pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE project_daily_summaries ADD COLUMN score INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
|
||||
function version_44($pdo)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,12 @@ use Core\Security;
|
||||
use PDO;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 62;
|
||||
const VERSION = 63;
|
||||
|
||||
function version_63($pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE project_daily_summaries ADD COLUMN score INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
|
||||
function version_62($pdo)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ class ProjectDailySummarySubscriber extends Base implements EventSubscriberInter
|
||||
{
|
||||
return array(
|
||||
Task::EVENT_CREATE => array('execute', 0),
|
||||
Task::EVENT_UPDATE => array('execute', 0),
|
||||
Task::EVENT_CLOSE => array('execute', 0),
|
||||
Task::EVENT_OPEN => array('execute', 0),
|
||||
Task::EVENT_MOVE_COLUMN => array('execute', 0),
|
||||
|
||||
34
app/Template/analytic/burndown.php
Normal file
34
app/Template/analytic/burndown.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<div class="page-header">
|
||||
<h2><?= t('Burndown chart') ?></h2>
|
||||
</div>
|
||||
|
||||
<?php if (! $display_graph): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?php else: ?>
|
||||
<section id="analytic-burndown">
|
||||
<div id="chart" data-url="<?= $this->u('analytic', 'burndown', array('project_id' => $project['id'], 'from' => $values['from'], 'to' => $values['to'])) ?>"></div>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
|
||||
<hr/>
|
||||
|
||||
<form method="post" class="form-inline" action="<?= $this->u('analytic', 'burndown', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
|
||||
<?= $this->formCsrf() ?>
|
||||
|
||||
<div class="form-inline-group">
|
||||
<?= $this->formLabel(t('Start Date'), 'from') ?>
|
||||
<?= $this->formText('from', $values, array(), array('required', 'placeholder="'.$this->inList($date_format, $date_formats).'"'), 'form-date') ?>
|
||||
</div>
|
||||
|
||||
<div class="form-inline-group">
|
||||
<?= $this->formLabel(t('End Date'), 'to') ?>
|
||||
<?= $this->formText('to', $values, array(), array('required', 'placeholder="'.$this->inList($date_format, $date_formats).'"'), 'form-date') ?>
|
||||
</div>
|
||||
|
||||
<div class="form-inline-group">
|
||||
<input type="submit" value="<?= t('Execute') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="alert alert-info"><?= t('This chart show the task complexity over the time (Work Remaining).') ?></p>
|
||||
@@ -10,5 +10,8 @@
|
||||
<li>
|
||||
<?= $this->a(t('Cumulative flow diagram'), 'analytic', 'cfd', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= $this->a(t('Burndown chart'), 'analytic', 'burndown', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
Reference in New Issue
Block a user