diff options
author | Frederic Guillot <fred@kanboard.net> | 2017-04-08 13:58:25 -0400 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2017-04-08 13:58:25 -0400 |
commit | d7b0cfbbe57fae9afbf9637afa7e54d3bf708747 (patch) | |
tree | ced408d01329538bd34b659018a7cd11e04aa982 /app | |
parent | fe9f3ba707d1caf9348ae17e0566eabd505fbce2 (diff) |
Improve dashboard
Diffstat (limited to 'app')
-rw-r--r-- | app/Controller/DashboardController.php | 58 | ||||
-rw-r--r-- | app/Core/Base.php | 3 | ||||
-rw-r--r-- | app/Formatter/TaskListSubtaskAssigneeFormatter.php | 13 | ||||
-rw-r--r-- | app/Helper/LayoutHelper.php | 13 | ||||
-rw-r--r-- | app/Model/ProjectModel.php | 21 | ||||
-rw-r--r-- | app/Model/SubtaskModel.php | 9 | ||||
-rw-r--r-- | app/Pagination/ProjectPagination.php | 35 | ||||
-rw-r--r-- | app/Pagination/SubtaskPagination.php | 35 | ||||
-rw-r--r-- | app/Pagination/TaskPagination.php | 39 | ||||
-rw-r--r-- | app/ServiceProvider/ClassProvider.php | 3 | ||||
-rw-r--r-- | app/Template/dashboard/layout.php | 29 | ||||
-rw-r--r-- | app/Template/dashboard/overview.php (renamed from app/Template/dashboard/show.php) | 59 | ||||
-rw-r--r-- | app/Template/dashboard/projects.php | 27 | ||||
-rw-r--r-- | app/Template/dashboard/sidebar.php | 17 | ||||
-rw-r--r-- | app/Template/dashboard/subtasks.php | 48 | ||||
-rw-r--r-- | app/Template/dashboard/tasks.php | 38 |
16 files changed, 419 insertions, 28 deletions
diff --git a/app/Controller/DashboardController.php b/app/Controller/DashboardController.php index ef7d8772..0ff6f20e 100644 --- a/app/Controller/DashboardController.php +++ b/app/Controller/DashboardController.php @@ -19,10 +19,60 @@ class DashboardController extends BaseController { $user = $this->getUser(); - $this->response->html($this->helper->layout->app('dashboard/show', array( - 'title' => t('Dashboard for %s', $this->helper->user->getFullname($user)), - 'user' => $user, - 'results' => $this->dashboardPagination->getOverview($user['id']), + $this->response->html($this->helper->layout->dashboard('dashboard/overview', array( + 'title' => t('Dashboard for %s', $this->helper->user->getFullname($user)), + 'user' => $user, + 'overview_paginator' => $this->dashboardPagination->getOverview($user['id']), + 'project_paginator' => $this->projectPagination->getDashboardPaginator($user['id'], 'show', 10), + ))); + } + + /** + * My tasks + * + * @access public + */ + public function tasks() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->dashboard('dashboard/tasks', array( + 'title' => t('Tasks overview for %s', $this->helper->user->getFullname($user)), + 'paginator' => $this->taskPagination->getDashboardPaginator($user['id'], 'tasks', 50), + 'user' => $user, + ))); + } + + /** + * My subtasks + * + * @access public + */ + public function subtasks() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->dashboard('dashboard/subtasks', array( + 'title' => t('Subtasks overview for %s', $this->helper->user->getFullname($user)), + 'paginator' => $this->subtaskPagination->getDashboardPaginator($user['id']), + 'user' => $user, + 'nb_subtasks' => $this->subtaskModel->countByAssigneeAndTaskStatus($this->userSession->getId()), + ))); + } + + /** + * My projects + * + * @access public + */ + public function projects() + { + $user = $this->getUser(); + + $this->response->html($this->helper->layout->dashboard('dashboard/projects', array( + 'title' => t('Projects overview for %s', $this->helper->user->getFullname($user)), + 'paginator' => $this->projectPagination->getDashboardPaginator($user['id'], 'projects', 25), + 'user' => $user, ))); } } diff --git a/app/Core/Base.php b/app/Core/Base.php index e3dc2f23..c11faee2 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -150,6 +150,9 @@ use Pimple\Container; * @property \Kanboard\Model\UserUnreadNotificationModel $userUnreadNotificationModel * @property \Kanboard\Model\UserMetadataModel $userMetadataModel * @property \Kanboard\Pagination\DashboardPagination $dashboardPagination + * @property \Kanboard\Pagination\ProjectPagination $projectPagination + * @property \Kanboard\Pagination\TaskPagination $taskPagination + * @property \Kanboard\Pagination\SubtaskPagination $subtaskPagination * @property \Kanboard\Pagination\UserPagination $userPagination * @property \Kanboard\Validator\ActionValidator $actionValidator * @property \Kanboard\Validator\AuthValidator $authValidator diff --git a/app/Formatter/TaskListSubtaskAssigneeFormatter.php b/app/Formatter/TaskListSubtaskAssigneeFormatter.php index 50b08cd8..73391766 100644 --- a/app/Formatter/TaskListSubtaskAssigneeFormatter.php +++ b/app/Formatter/TaskListSubtaskAssigneeFormatter.php @@ -11,6 +11,7 @@ namespace Kanboard\Formatter; class TaskListSubtaskAssigneeFormatter extends TaskListFormatter { protected $userId = 0; + protected $withoutEmptyTasks = false; /** * Set assignee @@ -24,6 +25,12 @@ class TaskListSubtaskAssigneeFormatter extends TaskListFormatter return $this; } + public function withoutEmptyTasks() + { + $this->withoutEmptyTasks = true; + return $this; + } + /** * Apply formatter * @@ -38,6 +45,12 @@ class TaskListSubtaskAssigneeFormatter extends TaskListFormatter $subtasks = array_column_index($subtasks, 'task_id'); array_merge_relation($tasks, $subtasks, 'subtasks', 'id'); + if ($this->withoutEmptyTasks) { + $tasks = array_filter($tasks, function (array $task) { + return count($task['subtasks']) > 0; + }); + } + return $tasks; } } diff --git a/app/Helper/LayoutHelper.php b/app/Helper/LayoutHelper.php index 52c83fec..91745f58 100644 --- a/app/Helper/LayoutHelper.php +++ b/app/Helper/LayoutHelper.php @@ -141,6 +141,19 @@ class LayoutHelper extends Base } /** + * Common layout for dashboard views + * + * @access public + * @param string $template + * @param array $params + * @return string + */ + public function dashboard($template, array $params) + { + return $this->subLayout('dashboard/layout', 'dashboard/sidebar', $template, $params); + } + + /** * Common layout for analytic views * * @access public diff --git a/app/Model/ProjectModel.php b/app/Model/ProjectModel.php index cabfee8a..7f489c75 100644 --- a/app/Model/ProjectModel.php +++ b/app/Model/ProjectModel.php @@ -304,6 +304,27 @@ class ProjectModel extends Base } /** + * Get project summary for a list of project + * + * @access public + * @param array $project_ids List of project id + * @return \PicoDb\Table + */ + public function getQueryColumnStats(array $project_ids) + { + if (empty($project_ids)) { + return $this->db->table(ProjectModel::TABLE)->eq(ProjectModel::TABLE.'.id', 0); + } + + return $this->db + ->table(ProjectModel::TABLE) + ->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name') + ->join(UserModel::TABLE, 'id', 'owner_id') + ->in(self::TABLE.'.id', $project_ids) + ->callback(array($this, 'applyColumnStats')); + } + + /** * Get query for list of project without column statistics * * @access public diff --git a/app/Model/SubtaskModel.php b/app/Model/SubtaskModel.php index 40cb517d..1e652ae2 100644 --- a/app/Model/SubtaskModel.php +++ b/app/Model/SubtaskModel.php @@ -88,6 +88,15 @@ class SubtaskModel extends Base ->asc(self::TABLE.'.position'); } + public function countByAssigneeAndTaskStatus($userId) + { + return $this->db->table(self::TABLE) + ->eq('user_id', $userId) + ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN) + ->join(Taskmodel::TABLE, 'id', 'task_id') + ->count(); + } + /** * Get all subtasks for a given task * diff --git a/app/Pagination/ProjectPagination.php b/app/Pagination/ProjectPagination.php new file mode 100644 index 00000000..8f1fa87c --- /dev/null +++ b/app/Pagination/ProjectPagination.php @@ -0,0 +1,35 @@ +<?php + +namespace Kanboard\Pagination; + +use Kanboard\Core\Base; +use Kanboard\Core\Paginator; +use Kanboard\Model\ProjectModel; + +/** + * Class ProjectPagination + * + * @package Kanboard\Pagination + * @author Frederic Guillot + */ +class ProjectPagination extends Base +{ + /** + * Get dashboard pagination + * + * @access public + * @param integer $user_id + * @param string $method + * @param integer $max + * @return Paginator + */ + public function getDashboardPaginator($user_id, $method, $max) + { + return $this->paginator + ->setUrl('DashboardController', $method, array('pagination' => 'projects', 'user_id' => $user_id)) + ->setMax($max) + ->setOrder(ProjectModel::TABLE.'.name') + ->setQuery($this->projectModel->getQueryColumnStats($this->projectPermissionModel->getActiveProjectIds($user_id))) + ->calculateOnlyIf($this->request->getStringParam('pagination') === 'projects'); + } +} diff --git a/app/Pagination/SubtaskPagination.php b/app/Pagination/SubtaskPagination.php new file mode 100644 index 00000000..83593b5e --- /dev/null +++ b/app/Pagination/SubtaskPagination.php @@ -0,0 +1,35 @@ +<?php + +namespace Kanboard\Pagination; + +use Kanboard\Core\Base; +use Kanboard\Core\Paginator; +use Kanboard\Model\TaskModel; + +/** + * Class SubtaskPagination + * + * @package Kanboard\Pagination + * @author Frederic Guillot + */ +class SubtaskPagination extends Base +{ + /** + * Get dashboard pagination + * + * @access public + * @param integer $userId + * @return Paginator + */ + public function getDashboardPaginator($userId) + { + return $this->paginator + ->setUrl('DashboardController', 'subtasks', array('user_id' => $userId)) + ->setMax(50) + ->setOrder(TaskModel::TABLE.'.priority') + ->setDirection('DESC') + ->setFormatter($this->taskListSubtaskAssigneeFormatter->withUserId($userId)->withoutEmptyTasks()) + ->setQuery($this->taskFinderModel->getUserQuery($userId)) + ->calculate(); + } +} diff --git a/app/Pagination/TaskPagination.php b/app/Pagination/TaskPagination.php new file mode 100644 index 00000000..53e05c13 --- /dev/null +++ b/app/Pagination/TaskPagination.php @@ -0,0 +1,39 @@ +<?php + +namespace Kanboard\Pagination; + +use Kanboard\Core\Base; +use Kanboard\Core\Paginator; +use Kanboard\Model\TaskModel; + +/** + * Class TaskPagination + * + * @package Kanboard\Pagination + * @author Frederic Guillot + */ +class TaskPagination extends Base +{ + /** + * Get dashboard pagination + * + * @access public + * @param integer $userId + * @param string $method + * @param integer $max + * @return Paginator + */ + public function getDashboardPaginator($userId, $method, $max) + { + $query = $this->taskFinderModel->getUserQuery($userId); + $this->hook->reference('pagination:dashboard:task:query', $query); + + return $this->paginator + ->setUrl('DashboardController', $method, array('pagination' => 'tasks', 'user_id' => $userId)) + ->setMax($max) + ->setOrder(TaskModel::TABLE.'.id') + ->setQuery($query) + ->setFormatter($this->taskListFormatter) + ->calculateOnlyIf($this->request->getStringParam('pagination') === 'tasks'); + } +} diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index f510b80b..f8bb3ae4 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -130,6 +130,9 @@ class ClassProvider implements ServiceProviderInterface ), 'Pagination' => array( 'DashboardPagination', + 'ProjectPagination', + 'SubtaskPagination', + 'TaskPagination', 'UserPagination', ), 'Core' => array( diff --git a/app/Template/dashboard/layout.php b/app/Template/dashboard/layout.php new file mode 100644 index 00000000..45b52451 --- /dev/null +++ b/app/Template/dashboard/layout.php @@ -0,0 +1,29 @@ +<section id="main"> + <div class="page-header"> + <ul> + <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?> + <li> + <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?> + </li> + <?php endif ?> + <?php if ($this->app->config('disable_private_project', 0) == 0): ?> + <li> + <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?> + </li> + <?php endif ?> + <li> + <?= $this->url->icon('folder', t('Project management'), 'ProjectListController', 'show') ?> + </li> + <li> + <?= $this->modal->medium('dashboard', t('My activity stream'), 'ActivityController', 'user') ?> + </li> + <?= $this->hook->render('template:dashboard:page-header:menu', array('user' => $user)) ?> + </ul> + </div> + <section class="sidebar-container" id="dashboard"> + <?= $this->render($sidebar_template, array('user' => $user)) ?> + <div class="sidebar-content"> + <?= $content_for_sublayout ?> + </div> + </section> +</section> diff --git a/app/Template/dashboard/show.php b/app/Template/dashboard/overview.php index 64b90516..e732a387 100644 --- a/app/Template/dashboard/show.php +++ b/app/Template/dashboard/overview.php @@ -1,25 +1,3 @@ -<div class="page-header"> - <ul> - <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?> - <li> - <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?> - </li> - <?php endif ?> - <?php if ($this->app->config('disable_private_project', 0) == 0): ?> - <li> - <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?> - </li> - <?php endif ?> - <li> - <?= $this->url->icon('folder', t('Project management'), 'ProjectListController', 'show') ?> - </li> - <li> - <?= $this->modal->medium('dashboard', t('My activity stream'), 'ActivityController', 'user') ?> - </li> - <?= $this->hook->render('template:dashboard:page-header:menu', array('user' => $user)) ?> - </ul> -</div> - <div class="filter-box margin-bottom"> <form method="get" action="<?= $this->url->dir() ?>" class="search"> <?= $this->form->hidden('controller', array('controller' => 'SearchController')) ?> @@ -34,10 +12,43 @@ </form> </div> -<?php if (empty($results)): ?> +<?php if (! $project_paginator->isEmpty()): ?> + <div class="table-list"> + <?= $this->render('project_list/header', array('paginator' => $project_paginator)) ?> + <?php foreach ($project_paginator->getCollection() as $project): ?> + <div class="table-list-row table-border-left"> + <div> + <?php if ($this->user->hasProjectAccess('ProjectViewController', 'show', $project['id'])): ?> + <?= $this->render('project/dropdown', array('project' => $project)) ?> + <?php else: ?> + <strong><?= '#'.$project['id'] ?></strong> + <?php endif ?> + + <span class="table-list-title <?= $project['is_active'] == 0 ? 'status-closed' : '' ?>"> + <?= $this->url->link($this->text->e($project['name']), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?> + </span> + + <?php if ($project['is_private']): ?> + <i class="fa fa-lock fa-fw" title="<?= t('Private project') ?>"></i> + <?php endif ?> + </div> + <div class="table-list-details"> + <?php foreach ($project['columns'] as $column): ?> + <strong title="<?= t('Task count') ?>"><?= $column['nb_open_tasks'] ?></strong> + <small><?= $this->text->e($column['title']) ?></small> + <?php endforeach ?> + </div> + </div> + <?php endforeach ?> + </div> + + <?= $project_paginator ?> +<?php endif ?> + +<?php if (empty($overview_paginator)): ?> <p class="alert"><?= t('There is nothing assigned to you.') ?></p> <?php else: ?> - <?php foreach ($results as $result): ?> + <?php foreach ($overview_paginator as $result): ?> <?php if (! $result['paginator']->isEmpty()): ?> <div class="page-header"> <h2><?= $this->url->link($this->text->e($result['project_name']), 'BoardViewController', 'show', array('project_id' => $result['project_id'])) ?></h2> diff --git a/app/Template/dashboard/projects.php b/app/Template/dashboard/projects.php new file mode 100644 index 00000000..e84a9415 --- /dev/null +++ b/app/Template/dashboard/projects.php @@ -0,0 +1,27 @@ +<div class="page-header"> + <h2><?= $this->url->link(t('My projects'), 'DashboardController', 'projects', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2> +</div> +<?php if ($paginator->isEmpty()): ?> + <p class="alert"><?= t('Your are not member of any project.') ?></p> +<?php else: ?> + <div class="table-list"> + <?= $this->render('project_list/header', array('paginator' => $paginator)) ?> + <?php foreach ($paginator->getCollection() as $project): ?> + <div class="table-list-row table-border-left"> + <?= $this->render('project_list/project_title', array( + 'project' => $project, + )) ?> + + <?= $this->render('project_list/project_details', array( + 'project' => $project, + )) ?> + + <?= $this->render('project_list/project_icons', array( + 'project' => $project, + )) ?> + </div> + <?php endforeach ?> + </div> + + <?= $paginator ?> +<?php endif ?> diff --git a/app/Template/dashboard/sidebar.php b/app/Template/dashboard/sidebar.php new file mode 100644 index 00000000..7507b00d --- /dev/null +++ b/app/Template/dashboard/sidebar.php @@ -0,0 +1,17 @@ +<div class="sidebar"> + <ul> + <li <?= $this->app->checkMenuSelection('DashboardController', 'show') ?>> + <?= $this->url->link(t('Overview'), 'DashboardController', 'show', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('DashboardController', 'projects') ?>> + <?= $this->url->link(t('My projects'), 'DashboardController', 'projects', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('DashboardController', 'tasks') ?>> + <?= $this->url->link(t('My tasks'), 'DashboardController', 'tasks', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('DashboardController', 'subtasks') ?>> + <?= $this->url->link(t('My subtasks'), 'DashboardController', 'subtasks', array('user_id' => $user['id'])) ?> + </li> + <?= $this->hook->render('template:dashboard:sidebar', array('user' => $user)) ?> + </ul> +</div> diff --git a/app/Template/dashboard/subtasks.php b/app/Template/dashboard/subtasks.php new file mode 100644 index 00000000..ccc08c59 --- /dev/null +++ b/app/Template/dashboard/subtasks.php @@ -0,0 +1,48 @@ +<div class="page-header"> + <h2><?= $this->url->link(t('My subtasks'), 'DashboardController', 'subtasks', array('user_id' => $user['id'])) ?> (<?= $nb_subtasks ?>)</h2> +</div> +<?php if ($nb_subtasks == 0): ?> + <p class="alert"><?= t('There is nothing assigned to you.') ?></p> +<?php else: ?> + <div class="table-list"> + <div class="table-list-header"> + <div class="table-list-header-count"> + <?php if ($nb_subtasks > 1): ?> + <?= t('%d subtasks', $nb_subtasks) ?> + <?php else: ?> + <?= t('%d subtask', $nb_subtasks) ?> + <?php endif ?> + </div> + <div class="table-list-header-menu"> + <div class="dropdown"> + <a href="#" class="dropdown-menu dropdown-menu-link-icon"><strong><?= t('Sort') ?> <i class="fa fa-caret-down"></i></strong></a> + <ul> + <li> + <?= $paginator->order(t('Task ID'), \Kanboard\Model\TaskModel::TABLE.'.id') ?> + </li> + <li> + <?= $paginator->order(t('Title'), \Kanboard\Model\TaskModel::TABLE.'.title') ?> + </li> + <li> + <?= $paginator->order(t('Priority'), \Kanboard\Model\TaskModel::TABLE.'.priority') ?> + </li> + </ul> + </div> + </div> + </div> + + <?php foreach ($paginator->getCollection() as $task): ?> + <div class="table-list-row color-<?= $task['color_id'] ?>"> + <?= $this->render('task_list/task_title', array( + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_subtasks', array( + 'task' => $task, + )) ?> + </div> + <?php endforeach ?> + </div> + + <?= $paginator ?> +<?php endif ?> diff --git a/app/Template/dashboard/tasks.php b/app/Template/dashboard/tasks.php new file mode 100644 index 00000000..23aef990 --- /dev/null +++ b/app/Template/dashboard/tasks.php @@ -0,0 +1,38 @@ +<div class="page-header"> + <h2><?= $this->url->link(t('My tasks'), 'DashboardController', 'tasks', array('user_id' => $user['id'])) ?> (<?= $paginator->getTotal() ?>)</h2> +</div> +<?php if ($paginator->isEmpty()): ?> + <p class="alert"><?= t('There is nothing assigned to you.') ?></p> +<?php else: ?> + <div class="table-list"> + <?= $this->render('task_list/header', array( + 'paginator' => $paginator, + )) ?> + + <?php foreach ($paginator->getCollection() as $task): ?> + <div class="table-list-row color-<?= $task['color_id'] ?>"> + <?= $this->render('task_list/task_title', array( + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_details', array( + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_avatars', array( + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_icons', array( + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_subtasks', array( + 'task' => $task, + )) ?> + </div> + <?php endforeach ?> + </div> + + <?= $paginator ?> +<?php endif ?> |