diff options
-rw-r--r-- | assets/css/app.css | 5 | ||||
-rw-r--r-- | assets/js/board.js | 54 | ||||
-rw-r--r-- | controllers/board.php | 37 | ||||
-rw-r--r-- | locales/es_ES/translations.php | 11 | ||||
-rw-r--r-- | locales/fr_FR/translations.php | 11 | ||||
-rw-r--r-- | locales/pl_PL/translations.php | 11 | ||||
-rw-r--r-- | locales/pt_BR/translations.php | 11 | ||||
-rw-r--r-- | models/board.php | 8 | ||||
-rw-r--r-- | models/project.php | 10 | ||||
-rw-r--r-- | models/task.php | 10 | ||||
-rw-r--r-- | models/user.php | 7 | ||||
-rw-r--r-- | templates/board_index.php | 13 | ||||
-rw-r--r-- | templates/layout.php | 12 | ||||
-rw-r--r-- | vendor/PicoDb/Table.php | 15 |
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&action=tasks&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&action=tasks&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&action=edit&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&action=logout"><?= t('logout') ?></a> + <a href="?controller=user&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; |