Add graph for user repartition
This commit is contained in:
@@ -27,11 +27,11 @@ class Analytic extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show task distribution graph
|
* Show tasks distribution graph
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function repartition()
|
public function tasks()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
$metrics = $this->projectAnalytic->getTaskRepartition($project['id']);
|
$metrics = $this->projectAnalytic->getTaskRepartition($project['id']);
|
||||||
@@ -46,11 +46,39 @@ class Analytic extends Base
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->response->html($this->layout('analytic/repartition', array(
|
$this->response->html($this->layout('analytic/tasks', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'metrics' => $metrics,
|
'metrics' => $metrics,
|
||||||
'title' => t('Task repartition for "%s"', $project['name']),
|
'title' => t('Task repartition for "%s"', $project['name']),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show users repartition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
$project = $this->getProject();
|
||||||
|
$metrics = $this->projectAnalytic->getUserRepartition($project['id']);
|
||||||
|
|
||||||
|
if ($this->request->isAjax()) {
|
||||||
|
$this->response->json(array(
|
||||||
|
'metrics' => $metrics,
|
||||||
|
'labels' => array(
|
||||||
|
'user' => t('User'),
|
||||||
|
'nb_tasks' => t('Number of tasks'),
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->response->html($this->layout('analytic/users', array(
|
||||||
|
'project' => $project,
|
||||||
|
'metrics' => $metrics,
|
||||||
|
'title' => t('User repartition for "%s"', $project['name']),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
'Analytics' => 'Analytique',
|
'Analytics' => 'Analytique',
|
||||||
'Subtask' => 'Sous-tâche',
|
'Subtask' => 'Sous-tâche',
|
||||||
'My subtasks' => 'Mes sous-tâches',
|
'My subtasks' => 'Mes sous-tâches',
|
||||||
|
'User repartition' => 'Répartition des utilisateurs',
|
||||||
|
'User repartition for "%s"' => 'Répartition des utilisateurs pour « %s »',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -573,4 +573,6 @@ return array(
|
|||||||
// 'Analytics' => '',
|
// 'Analytics' => '',
|
||||||
// 'Subtask' => '',
|
// 'Subtask' => '',
|
||||||
// 'My subtasks' => '',
|
// 'My subtasks' => '',
|
||||||
|
// 'User repartition' => '',
|
||||||
|
// 'User repartition for "%s"' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Acl extends Base
|
|||||||
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'),
|
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'),
|
||||||
'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'),
|
'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'),
|
||||||
'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'),
|
'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'),
|
||||||
'analytic' => array('repartition'),
|
'analytic' => array('tasks', 'users'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Model;
|
|||||||
class ProjectAnalytic extends Base
|
class ProjectAnalytic extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get task repartition
|
* Get tasks repartition
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
@@ -40,4 +40,41 @@ class ProjectAnalytic extends Base
|
|||||||
|
|
||||||
return $metrics;
|
return $metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get users repartition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUserRepartition($project_id)
|
||||||
|
{
|
||||||
|
$metrics = array();
|
||||||
|
$total = 0;
|
||||||
|
$tasks = $this->taskFinder->getAll($project_id);
|
||||||
|
$users = $this->projectPermission->getMemberList($project_id);
|
||||||
|
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
|
||||||
|
$user = $users[$task['owner_id']];
|
||||||
|
$total++;
|
||||||
|
|
||||||
|
if (! isset($metrics[$user])) {
|
||||||
|
$metrics[$user] = array(
|
||||||
|
'nb_tasks' => 0,
|
||||||
|
'percentage' => 0,
|
||||||
|
'user' => $user,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$metrics[$user]['nb_tasks']++;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($metrics as &$metric) {
|
||||||
|
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values($metrics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
<h2><?= t('Reportings') ?></h2>
|
<h2><?= t('Reportings') ?></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<?= Helper\a(t('Task distribution'), 'analytic', 'repartition', array('project_id' => $project['id'])) ?>
|
<?= Helper\a(t('Task distribution'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<?= Helper\a(t('User repartition'), 'analytic', 'users', array('project_id' => $project['id'])) ?>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h2><?= t('Task distribution') ?></h2>
|
<h2><?= t('Task distribution') ?></h2>
|
||||||
</div>
|
</div>
|
||||||
<section id="analytic-repartition">
|
<section id="analytic-task-repartition">
|
||||||
|
|
||||||
<div id="chart" data-url="<?= Helper\u('analytic', 'repartition', array('project_id' => $project['id'])) ?>"></div>
|
<div id="chart" data-url="<?= Helper\u('analytic', 'tasks', array('project_id' => $project['id'])) ?>"></div>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
29
app/Template/analytic/users.php
Normal file
29
app/Template/analytic/users.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('User repartition') ?></h2>
|
||||||
|
</div>
|
||||||
|
<section id="analytic-user-repartition">
|
||||||
|
|
||||||
|
<div id="chart" data-url="<?= Helper\u('analytic', 'users', array('project_id' => $project['id'])) ?>"></div>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th><?= t('User') ?></th>
|
||||||
|
<th><?= t('Number of tasks') ?></th>
|
||||||
|
<th><?= t('Percentage') ?></th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($metrics as $metric): ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<?= Helper\escape($metric['user']) ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?= $metric['nb_tasks'] ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?= n($metric['percentage']) ?>%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</section>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<i class="fa fa-line-chart fa-fw"></i>
|
<i class="fa fa-line-chart fa-fw"></i>
|
||||||
<?= Helper\a(t('Analytics'), 'analytic', 'repartition', array('project_id' => $project['id'])) ?>
|
<?= Helper\a(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
|
||||||
</li>
|
</li>
|
||||||
<?php if (Helper\is_admin()): ?>
|
<?php if (Helper\is_admin()): ?>
|
||||||
<li><i class="fa fa-cog fa-fw"></i>
|
<li><i class="fa fa-cog fa-fw"></i>
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ Kanboard.Analytic = (function() {
|
|||||||
return {
|
return {
|
||||||
Init: function() {
|
Init: function() {
|
||||||
|
|
||||||
if (Kanboard.Exists("analytic-repartition")) {
|
if (Kanboard.Exists("analytic-task-repartition")) {
|
||||||
Kanboard.Analytic.Repartition.Init();
|
Kanboard.Analytic.TaskRepartition.Init();
|
||||||
|
}
|
||||||
|
else if (Kanboard.Exists("analytic-user-repartition")) {
|
||||||
|
Kanboard.Analytic.UserRepartition.Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
Kanboard.Analytic.Repartition = (function() {
|
Kanboard.Analytic.TaskRepartition = (function() {
|
||||||
|
|
||||||
function fetchData()
|
function fetchData()
|
||||||
{
|
{
|
||||||
@@ -56,3 +59,48 @@ Kanboard.Analytic.Repartition = (function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
Kanboard.Analytic.UserRepartition = (function() {
|
||||||
|
|
||||||
|
function fetchData()
|
||||||
|
{
|
||||||
|
jQuery.getJSON($("#chart").attr("data-url"), function(data) {
|
||||||
|
drawGraph(data.metrics, data.labels);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGraph(metrics, labels)
|
||||||
|
{
|
||||||
|
var series = prepareSeries(metrics, labels);
|
||||||
|
|
||||||
|
var svg = dimple.newSvg("#chart", 700, 350);
|
||||||
|
|
||||||
|
var chart = new dimple.chart(svg, series);
|
||||||
|
chart.addMeasureAxis("p", labels["nb_tasks"]);
|
||||||
|
var ring = chart.addSeries(labels["user"], dimple.plot.pie);
|
||||||
|
ring.innerRadius = "50%";
|
||||||
|
chart.addLegend(0, 0, 100, 100, "left");
|
||||||
|
chart.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareSeries(metrics, labels)
|
||||||
|
{
|
||||||
|
var series = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
|
||||||
|
var serie = {};
|
||||||
|
serie[labels["nb_tasks"]] = metrics[i]["nb_tasks"];
|
||||||
|
serie[labels["user"]] = metrics[i]["user"];
|
||||||
|
|
||||||
|
series.push(serie);
|
||||||
|
}
|
||||||
|
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Init: fetchData
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|||||||
@@ -273,15 +273,18 @@ Kanboard.Analytic = (function() {
|
|||||||
return {
|
return {
|
||||||
Init: function() {
|
Init: function() {
|
||||||
|
|
||||||
if (Kanboard.Exists("analytic-repartition")) {
|
if (Kanboard.Exists("analytic-task-repartition")) {
|
||||||
Kanboard.Analytic.Repartition.Init();
|
Kanboard.Analytic.TaskRepartition.Init();
|
||||||
|
}
|
||||||
|
else if (Kanboard.Exists("analytic-user-repartition")) {
|
||||||
|
Kanboard.Analytic.UserRepartition.Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
Kanboard.Analytic.Repartition = (function() {
|
Kanboard.Analytic.TaskRepartition = (function() {
|
||||||
|
|
||||||
function fetchData()
|
function fetchData()
|
||||||
{
|
{
|
||||||
@@ -324,6 +327,51 @@ Kanboard.Analytic.Repartition = (function() {
|
|||||||
Init: fetchData
|
Init: fetchData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
Kanboard.Analytic.UserRepartition = (function() {
|
||||||
|
|
||||||
|
function fetchData()
|
||||||
|
{
|
||||||
|
jQuery.getJSON($("#chart").attr("data-url"), function(data) {
|
||||||
|
drawGraph(data.metrics, data.labels);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGraph(metrics, labels)
|
||||||
|
{
|
||||||
|
var series = prepareSeries(metrics, labels);
|
||||||
|
|
||||||
|
var svg = dimple.newSvg("#chart", 700, 350);
|
||||||
|
|
||||||
|
var chart = new dimple.chart(svg, series);
|
||||||
|
chart.addMeasureAxis("p", labels["nb_tasks"]);
|
||||||
|
var ring = chart.addSeries(labels["user"], dimple.plot.pie);
|
||||||
|
ring.innerRadius = "50%";
|
||||||
|
chart.addLegend(0, 0, 100, 100, "left");
|
||||||
|
chart.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareSeries(metrics, labels)
|
||||||
|
{
|
||||||
|
var series = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
|
||||||
|
var serie = {};
|
||||||
|
serie[labels["nb_tasks"]] = metrics[i]["nb_tasks"];
|
||||||
|
serie[labels["user"]] = metrics[i]["user"];
|
||||||
|
|
||||||
|
series.push(serie);
|
||||||
|
}
|
||||||
|
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Init: fetchData
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
// Initialization
|
// Initialization
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user