summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/css/app.css5
-rw-r--r--assets/js/board.js54
-rw-r--r--controllers/board.php37
-rw-r--r--locales/es_ES/translations.php11
-rw-r--r--locales/fr_FR/translations.php11
-rw-r--r--locales/pl_PL/translations.php11
-rw-r--r--locales/pt_BR/translations.php11
-rw-r--r--models/board.php8
-rw-r--r--models/project.php10
-rw-r--r--models/task.php10
-rw-r--r--models/user.php7
-rw-r--r--templates/board_index.php13
-rw-r--r--templates/layout.php12
-rw-r--r--vendor/PicoDb/Table.php15
14 files changed, 158 insertions, 57 deletions
diff --git a/assets/css/app.css b/assets/css/app.css
index f3a44c92..a406fa4d 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -468,6 +468,11 @@ nav .active a {
background-color: red;
}
+a.filter-on {
+ font-weight: bold;
+ color: #333;
+}
+
.task-title {
margin-top: 10px;
font-size: 110%;
diff --git a/assets/js/board.js b/assets/js/board.js
index 3c5ec51c..a030a5fb 100644
--- a/assets/js/board.js
+++ b/assets/js/board.js
@@ -208,6 +208,8 @@
});
}
+ // Drag and drop events
+
var dragSrcItem = null;
var dragSrcColumn = null;
@@ -235,4 +237,56 @@
});
});
+ // Filtering
+
+ function getSelectedUserFilter()
+ {
+ var select = document.getElementById("form-user_id");
+ return select.options[select.selectedIndex].value;
+ }
+
+ function hasDueDateFilter()
+ {
+ var dateFilter = document.getElementById("filter-due-date");
+ return dateFilter.classList.contains("filter-on");
+ }
+
+ function applyFilter(selectedUserId, filterDueDate)
+ {
+ [].forEach.call(document.querySelectorAll('[data-task-id]'), function (item) {
+
+ var ownerId = item.getAttribute("data-owner-id");
+ var dueDate = item.getAttribute("data-due-date");
+
+ if (ownerId != selectedUserId && selectedUserId != -1) {
+ item.style.opacity = "0.2";
+ }
+ else {
+ item.style.opacity = "1.0";
+ }
+
+ if (filterDueDate && dueDate == "") {
+ item.style.opacity = "0.2";
+ }
+ });
+ }
+
+ var userFilter = document.getElementById("form-user_id");
+ var dateFilter = document.getElementById("filter-due-date");
+
+ if (userFilter) {
+ userFilter.onchange = function() {
+ applyFilter(getSelectedUserFilter(), hasDueDateFilter());
+ };
+ }
+
+ if (dateFilter) {
+
+ dateFilter.onclick = function(e) {
+ dateFilter.classList.toggle("filter-on");
+ applyFilter(getSelectedUserFilter(), hasDueDateFilter());
+ e.preventDefault();
+ };
+ }
+
}());
diff --git a/controllers/board.php b/controllers/board.php
index 941e987b..4fae32ea 100644
--- a/controllers/board.php
+++ b/controllers/board.php
@@ -121,7 +121,7 @@ class Board extends Base
}
/**
- * Display the default user project or the first project
+ * Redirect the user to the default project
*
* @access public
*/
@@ -150,16 +150,7 @@ class Board extends Base
list($project_id, $project_name) = each($projects);
}
- $this->checkProjectPermissions($project_id);
-
- $this->response->html($this->template->layout('board_index', array(
- 'projects' => $projects,
- 'current_project_id' => $project_id,
- 'current_project_name' => $project_name,
- 'columns' => $this->board->get($project_id),
- 'menu' => 'boards',
- 'title' => $project_name
- )));
+ $this->response->redirect('?controller=board&action=show&project_id='.$project_id);
}
/**
@@ -169,26 +160,36 @@ class Board extends Base
*/
public function show()
{
+ $project_id = $this->request->getIntegerParam('project_id');
+ $user_id = $this->request->getIntegerParam('user_id', \Model\User::EVERYBODY_ID);
+
+ $this->checkProjectPermissions($project_id);
$projects = $this->project->getListByStatus(\Model\Project::ACTIVE);
if ($this->acl->isRegularUser()) {
$projects = $this->project->filterListByAccess($projects, $this->acl->getUserId());
}
- $project_id = $this->request->getIntegerParam('project_id');
+ if (! isset($projects[$project_id])) {
+ $this->notfound();
+ }
- $this->checkProjectPermissions($project_id);
- if (! isset($projects[$project_id])) $this->notfound();
+ $filters = array();
+ $users = $this->project->getUsersList($project_id, true, true);
- $project_name = $projects[$project_id];
+ if ($user_id !== \Model\User::EVERYBODY_ID && in_array($user_id, array_keys($users))) {
+ $filters[] = array('column' => 'owner_id', 'operator' => 'eq', 'value' => $user_id);
+ }
$this->response->html($this->template->layout('board_index', array(
+ 'users' => $users,
+ 'filters' => array('user_id' => $user_id),
'projects' => $projects,
'current_project_id' => $project_id,
- 'current_project_name' => $project_name,
- 'columns' => $this->board->get($project_id),
+ 'current_project_name' => $projects[$project_id],
+ 'columns' => $this->board->get($project_id, $filters),
'menu' => 'boards',
- 'title' => $project_name
+ 'title' => $projects[$project_id]
)));
}
diff --git a/locales/es_ES/translations.php b/locales/es_ES/translations.php
index 35a3367f..8b331c49 100644
--- a/locales/es_ES/translations.php
+++ b/locales/es_ES/translations.php
@@ -43,7 +43,7 @@ return array(
'Access Forbidden' => 'Acceso denegado',
'Only administrators can access to this page.' => 'Solo los administradores pueden acceder a esta pagina.',
'Edit user' => 'Editar un usuario',
- 'logout' => 'salir',
+ 'Logout' => 'Salir',
'Bad username or password' => 'Usuario o contraseña incorecto',
'users' => 'usuarios',
'projects' => 'proyectos',
@@ -69,7 +69,7 @@ return array(
'New project' => 'Nuevo proyecto',
'Do you really want to remove this project: "%s"?' => '¿Realmente desea eliminar este proyecto: « %s » ?',
'Remove project' => 'Suprimir el proyecto',
- 'boards' => 'tableros',
+ 'Boards' => 'Tableros',
'Edit the board for "%s"' => 'Modificar el tablero por « %s »',
'All projects' => 'Todos los proyectos',
'Change columns' => 'Cambiar las columnas',
@@ -84,7 +84,7 @@ return array(
'Unable to remove this column.' => 'No se puede suprimir esta columna.',
'Do you really want to remove this column: "%s"?' => '¿Realmente desea eliminar esta columna : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => '¡Esta acción suprimirá todas las tareas asociadas a esta columna!',
- 'settings' => 'preferencias',
+ 'Settings' => 'Preferencias',
'Application settings' => 'Parámetros de la aplicación',
'Language' => 'Idioma',
'Webhooks token:' => 'Identificador (token) para los webhooks :',
@@ -175,7 +175,7 @@ return array(
'Date completed' => 'Fecha terminada',
'Id' => 'Identificador',
'No task' => 'Ninguna tarea',
- 'completed tasks' => 'tareas terminadas',
+ 'Completed tasks' => 'Tareas terminadas',
'List of projects' => 'Lista de los proyectos',
'Completed tasks for "%s"' => 'Tarea completada por « %s »',
'%d closed tasks' => '%d tareas completadas',
@@ -280,4 +280,7 @@ return array(
// 'Expiration date' => '',
// 'Remember Me' => '',
// 'Creation date' => '',
+ // 'Filter by user' => '',
+ // 'Filter by due date' => ',
+ // 'Everybody' => '',
);
diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php
index cb9c402c..563ccc91 100644
--- a/locales/fr_FR/translations.php
+++ b/locales/fr_FR/translations.php
@@ -43,7 +43,7 @@ return array(
'Access Forbidden' => 'Accès interdit',
'Only administrators can access to this page.' => 'Uniquement les administrateurs peuvent accéder à cette page.',
'Edit user' => 'Modifier un utilisateur',
- 'logout' => 'déconnexion',
+ 'Logout' => 'Déconnexion',
'Bad username or password' => 'Identifiant ou mot de passe incorrect',
'users' => 'utilisateurs',
'projects' => 'projets',
@@ -69,7 +69,7 @@ return array(
'New project' => 'Nouveau projet',
'Do you really want to remove this project: "%s"?' => 'Voulez-vous vraiment supprimer ce projet : « %s » ?',
'Remove project' => 'Supprimer le projet',
- 'boards' => 'tableaux',
+ 'Boards' => 'Tableaux',
'Edit the board for "%s"' => 'Modifier le tableau pour « %s »',
'All projects' => 'Tous les projets',
'Change columns' => 'Changer les colonnes',
@@ -84,7 +84,7 @@ return array(
'Unable to remove this column.' => 'Impossible de supprimer cette colonne.',
'Do you really want to remove this column: "%s"?' => 'Voulez vraiment supprimer cette colonne : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Cette action va supprimer toutes les tâches associées à cette colonne !',
- 'settings' => 'préférences',
+ 'Settings' => 'Préférences',
'Application settings' => 'Paramètres de l\'application',
'Language' => 'Langue',
'Webhooks token:' => 'Jeton de securité pour les webhooks :',
@@ -175,7 +175,7 @@ return array(
'Date completed' => 'Date de clôture',
'Id' => 'Identifiant',
'No task' => 'Aucune tâche',
- 'completed tasks' => 'tâches terminées',
+ 'Completed tasks' => 'Tâches terminées',
'List of projects' => 'Liste des projets',
'Completed tasks for "%s"' => 'Tâches terminées pour « %s »',
'%d closed tasks' => '%d tâches terminées',
@@ -280,4 +280,7 @@ return array(
'Expiration date' => 'Date d\'expiration',
'Remember Me' => 'Connexion automatique',
'Creation date' => 'Date de création',
+ 'Filter by user' => 'Filtrer par utilisateur',
+ 'Filter by due date' => 'Filtrer par date d\'échéance',
+ 'Everybody' => 'Tout le monde',
);
diff --git a/locales/pl_PL/translations.php b/locales/pl_PL/translations.php
index ef17041f..3ecbc471 100644
--- a/locales/pl_PL/translations.php
+++ b/locales/pl_PL/translations.php
@@ -43,7 +43,7 @@ return array(
'Access Forbidden' => 'Dostęp zabroniony',
'Only administrators can access to this page.' => 'Tylko administrator może wejść na tą stronę.',
'Edit user' => 'Edytuj użytkownika',
- 'logout' => 'wyloguj',
+ 'Logout' => 'Wyloguj',
'Bad username or password' => 'Zła nazwa uyżytkownika lub hasło',
'users' => 'użytkownicy',
'projects' => 'projekty',
@@ -69,7 +69,7 @@ return array(
'New project' => 'Nowy projekt',
'Do you really want to remove this project: "%s"?' => 'Na pewno chcesz usunąć projekt: "%s"?',
'Remove project' => 'Usuń projekt',
- 'boards' => 'tablice',
+ 'Boards' => 'Tablice',
'Edit the board for "%s"' => 'Edytuj tablię dla "%s"',
'All projects' => 'Wszystkie projekty',
'Change columns' => 'Zmień kolumny',
@@ -84,7 +84,7 @@ return array(
'Unable to remove this column.' => 'Nie udało się usunąć kolumny.',
'Do you really want to remove this column: "%s"?' => 'Na pewno chcesz usunąć kolumnę: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Wszystkie zadania w kolumnie zostaną usunięte!',
- 'settings' => 'ustawienia',
+ 'Settings' => 'Ustawienia',
'Application settings' => 'Ustawienia aplikacji',
'Language' => 'Język',
'Webhooks token:' => 'Token :',
@@ -175,7 +175,7 @@ return array(
'Date completed' => 'Data zakończenia',
'Id' => 'Ident',
'No task' => 'Brak zadań',
- 'completed tasks' => 'ukończone zadania',
+ 'Completed tasks' => 'Ukończone zadania',
'List of projects' => 'Lista projektów',
'Completed tasks for "%s"' => 'Zadania zakończone dla "%s"',
'%d closed tasks' => '%d zamkniętych zadań',
@@ -285,4 +285,7 @@ return array(
'Expiration date' => 'Data zakończenia',
'Remember Me' => 'Pamiętaj mnie',
'Creation date' => 'Data utworzenia',
+ // 'Filter by user' => '',
+ // 'Filter by due date' => ',
+ // 'Everybody' => '',
);
diff --git a/locales/pt_BR/translations.php b/locales/pt_BR/translations.php
index 30351f3d..53ff4b15 100644
--- a/locales/pt_BR/translations.php
+++ b/locales/pt_BR/translations.php
@@ -43,7 +43,7 @@ return array(
'Access Forbidden' => 'Acesso negado',
'Only administrators can access to this page.' => 'Somente administradores têm acesso a esta página.',
'Edit user' => 'Editar usuário',
- 'logout' => 'logout',
+ 'Logout' => 'Logout',
'Bad username or password' => 'Usuário ou senha inválidos',
'users' => 'usuários',
'projects' => 'projetos',
@@ -69,7 +69,7 @@ return array(
'New project' => 'Novo projeto',
'Do you really want to remove this project: "%s"?' => 'Quer realmente remover este projeto: "%s" ?',
'Remove project' => 'Remover projeto',
- 'boards' => 'quadros',
+ 'Boards' => 'Quadros',
'Edit the board for "%s"' => 'Editar o quadro para "%s"',
'All projects' => 'Todos os projetos',
'Change columns' => 'Modificar colunas',
@@ -84,7 +84,7 @@ return array(
'Unable to remove this column.' => 'Impossível remover esta coluna.',
'Do you really want to remove this column: "%s"?' => 'Quer realmente remover esta coluna: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Esta ação vai REMOVER TODAS AS TAREFAS associadas a esta coluna!',
- 'settings' => 'preferências',
+ 'Settings' => 'Preferências',
'Application settings' => 'Preferências da aplicação',
'Language' => 'Idioma',
'Webhooks token:' => 'Token de webhooks:',
@@ -175,7 +175,7 @@ return array(
'Date completed' => 'Data de encerramento',
'Id' => 'Id',
'No task' => 'Nenhuma tarefa',
- 'completed tasks' => 'tarefas completadas',
+ 'Completed tasks' => 'tarefas completadas',
'List of projects' => 'Lista de projetos',
'Completed tasks for "%s"' => 'Tarefas completadas por "%s"',
'%d closed tasks' => '%d tarefas encerradas',
@@ -281,4 +281,7 @@ return array(
// 'Expiration date' => '',
// 'Remember Me' => '',
// 'Creation date' => '',
+ // 'Filter by user' => '',
+ // 'Filter by due date' => ',
+ // 'Everybody' => '',
);
diff --git a/models/board.php b/models/board.php
index af1f4f7a..01c3e832 100644
--- a/models/board.php
+++ b/models/board.php
@@ -176,16 +176,14 @@ class Board extends Base
* @param integer $project_id Project id
* @return array
*/
- public function get($project_id)
+ public function get($project_id, array $filters = array())
{
$this->db->startTransaction();
$columns = $this->getColumns($project_id);
- $filters = array(
- array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id),
- array('column' => 'is_active', 'operator' => 'eq', 'value' => Task::STATUS_OPEN),
- );
+ $filters[] = array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id);
+ $filters[] = array('column' => 'is_active', 'operator' => 'eq', 'value' => Task::STATUS_OPEN);
$taskModel = new Task($this->db, $this->event);
$tasks = $taskModel->find($filters);
diff --git a/models/project.php b/models/project.php
index b2a54571..8b7a2293 100644
--- a/models/project.php
+++ b/models/project.php
@@ -18,7 +18,7 @@ class Project extends Base
const INACTIVE = 0;
// Get a list of people that can by assigned for tasks
- public function getUsersList($project_id, $prepend = true)
+ public function getUsersList($project_id, $prepend_unassigned = true, $prepend_everybody = false)
{
$allowed_users = $this->getAllowedUsers($project_id);
$userModel = new User($this->db, $this->event);
@@ -27,8 +27,12 @@ class Project extends Base
$allowed_users = $userModel->getList();
}
- if ($prepend) {
- return array(t('Unassigned')) + $allowed_users;
+ if ($prepend_unassigned) {
+ $allowed_users = array(t('Unassigned')) + $allowed_users;
+ }
+
+ if ($prepend_everybody) {
+ $allowed_users = array(User::EVERYBODY_ID => t('Everybody')) + $allowed_users;
}
return $allowed_users;
diff --git a/models/task.php b/models/task.php
index c54e0cbc..b61fb13f 100644
--- a/models/task.php
+++ b/models/task.php
@@ -127,9 +127,10 @@ class Task extends Base
*
* @access public
* @param array $filters Filters: [ ['column' => '...', 'operator' => '...', 'value' => '...'], ... ]
+ * @param array $sorting Sorting: [ 'column' => 'date_creation', 'direction' => 'asc']
* @return array
*/
- public function find(array $filters)
+ public function find(array $filters, array $sorting = array())
{
$table = $this->db
->table(self::TABLE)
@@ -155,6 +156,13 @@ class Task extends Base
$table->$filter['operator']($filter['column'], $filter['value']);
}
+ if (empty($sorting)) {
+ $table->orderBy('tasks.position', 'ASC');
+ }
+ else {
+ $table->orderBy($sorting['column'], $sorting['direction']);
+ }
+
return $table->findAll();
}
diff --git a/models/user.php b/models/user.php
index c5017ac6..7334373c 100644
--- a/models/user.php
+++ b/models/user.php
@@ -23,6 +23,13 @@ class User extends Base
const TABLE = 'users';
/**
+ * Id used for everbody (filtering)
+ *
+ * @var integer
+ */
+ const EVERYBODY_ID = -1;
+
+ /**
* Get a specific user by id
*
* @access public
diff --git a/templates/board_index.php b/templates/board_index.php
index db0c4fec..fc7a4932 100644
--- a/templates/board_index.php
+++ b/templates/board_index.php
@@ -17,7 +17,12 @@
<div class="project-menu">
<ul>
- <li><a href="?controller=project&amp;action=tasks&amp;project_id=<?= $current_project_id ?>"><?= t('completed tasks') ?></a></li>
+ <li>
+ <?= t('Filter by user') ?>
+ <?= Helper\form_select('user_id', $users, $filters) ?>
+ </li>
+ <li><a href="#" id="filter-due-date"><?= t('Filter by due date') ?></a></li>
+ <li><a href="?controller=project&amp;action=tasks&amp;project_id=<?= $current_project_id ?>"><?= t('Completed tasks') ?></a></li>
</ul>
</div>
@@ -54,7 +59,11 @@
dropzone="copy">
<?php foreach ($column['tasks'] as $task): ?>
<div class="draggable-item" draggable="true">
- <div class="task task-<?= $task['color_id'] ?>" data-task-id="<?= $task['id'] ?>" title="<?= t('View this task') ?>">
+ <div class="task task-<?= $task['color_id'] ?>"
+ data-task-id="<?= $task['id'] ?>"
+ data-owner-id="<?= $task['owner_id'] ?>"
+ data-due-date="<?= $task['date_due'] ?>"
+ title="<?= t('View this task') ?>">
<a href="?controller=task&amp;action=edit&amp;task_id=<?= $task['id'] ?>" title="<?= t('Edit this task') ?>">#<?= $task['id'] ?></a> -
diff --git a/templates/layout.php b/templates/layout.php
index 0791b910..40c0b321 100644
--- a/templates/layout.php
+++ b/templates/layout.php
@@ -9,7 +9,7 @@
<link rel="apple-touch-icon" sizes="72x72" href="assets/img/touch-icon-ipad.png">
<link rel="apple-touch-icon" sizes="114x114" href="assets/img/touch-icon-iphone-retina.png">
<link rel="apple-touch-icon" sizes="144x144" href="assets/img/touch-icon-ipad-retina.png">
- <title><?= isset($title) ? Helper\escape($title) : 'Kanboard' ?></title>
+ <title><?= isset($title) ? Helper\escape($title).' - Kanboard' : 'Kanboard' ?></title>
<?php if (isset($auto_refresh)): ?>
<meta http-equiv="refresh" content="<?= AUTO_REFRESH_DURATION ?>" >
<?php endif ?>
@@ -23,19 +23,19 @@
<a class="logo" href="?">kan<span>board</span></a>
<ul>
<li <?= isset($menu) && $menu === 'boards' ? 'class="active"' : '' ?>>
- <a href="?controller=board"><?= t('boards') ?></a>
+ <a href="?controller=board"><?= t('Boards') ?></a>
</li>
<li <?= isset($menu) && $menu === 'projects' ? 'class="active"' : '' ?>>
- <a href="?controller=project"><?= t('projects') ?></a>
+ <a href="?controller=project"><?= t('Projects') ?></a>
</li>
<li <?= isset($menu) && $menu === 'users' ? 'class="active"' : '' ?>>
- <a href="?controller=user"><?= t('users') ?></a>
+ <a href="?controller=user"><?= t('Users') ?></a>
</li>
<li <?= isset($menu) && $menu === 'config' ? 'class="active"' : '' ?>>
- <a href="?controller=config"><?= t('settings') ?></a>
+ <a href="?controller=config"><?= t('Settings') ?></a>
</li>
<li>
- <a href="?controller=user&amp;action=logout"><?= t('logout') ?></a>
+ <a href="?controller=user&amp;action=logout"><?= t('Logout') ?></a>
(<?= Helper\escape($_SESSION['user']['username']) ?>)
</li>
</ul>
diff --git a/vendor/PicoDb/Table.php b/vendor/PicoDb/Table.php
index 494e350a..8a0ce644 100644
--- a/vendor/PicoDb/Table.php
+++ b/vendor/PicoDb/Table.php
@@ -4,6 +4,9 @@ namespace PicoDb;
class Table
{
+ const SORT_ASC = 'ASC';
+ const SORT_DESC = 'DESC';
+
private $table_name = '';
private $sql_limit = '';
private $sql_offset = '';
@@ -259,10 +262,10 @@ class Table
}
- public function orderBy($column, $order = 'ASC')
+ public function orderBy($column, $order = self::SORT_ASC)
{
$order = strtoupper($order);
- $order = $order === 'ASC' || $order === 'DESC' ? $order : 'ASC';
+ $order = $order === self::SORT_ASC || $order === self::SORT_DESC ? $order : self::SORT_ASC;
if ($this->sql_order === '') {
$this->sql_order = ' ORDER BY '.$this->db->escapeIdentifier($column).' '.$order;
@@ -278,10 +281,10 @@ class Table
public function asc($column)
{
if ($this->sql_order === '') {
- $this->sql_order = ' ORDER BY '.$this->db->escapeIdentifier($column).' ASC';
+ $this->sql_order = ' ORDER BY '.$this->db->escapeIdentifier($column).' '.self::SORT_ASC;
}
else {
- $this->sql_order .= ', '.$this->db->escapeIdentifier($column).' ASC';
+ $this->sql_order .= ', '.$this->db->escapeIdentifier($column).' '.self::SORT_ASC;
}
return $this;
@@ -291,10 +294,10 @@ class Table
public function desc($column)
{
if ($this->sql_order === '') {
- $this->sql_order = ' ORDER BY '.$this->db->escapeIdentifier($column).' DESC';
+ $this->sql_order = ' ORDER BY '.$this->db->escapeIdentifier($column).' '.self::SORT_DESC;
}
else {
- $this->sql_order .= ', '.$this->db->escapeIdentifier($column).' DESC';
+ $this->sql_order .= ', '.$this->db->escapeIdentifier($column).' '.self::SORT_DESC;
}
return $this;