summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Controller/DashboardController.php58
-rw-r--r--app/Core/Base.php3
-rw-r--r--app/Formatter/TaskListSubtaskAssigneeFormatter.php13
-rw-r--r--app/Helper/LayoutHelper.php13
-rw-r--r--app/Model/ProjectModel.php21
-rw-r--r--app/Model/SubtaskModel.php9
-rw-r--r--app/Pagination/ProjectPagination.php35
-rw-r--r--app/Pagination/SubtaskPagination.php35
-rw-r--r--app/Pagination/TaskPagination.php39
-rw-r--r--app/ServiceProvider/ClassProvider.php3
-rw-r--r--app/Template/dashboard/layout.php29
-rw-r--r--app/Template/dashboard/overview.php (renamed from app/Template/dashboard/show.php)59
-rw-r--r--app/Template/dashboard/projects.php27
-rw-r--r--app/Template/dashboard/sidebar.php17
-rw-r--r--app/Template/dashboard/subtasks.php48
-rw-r--r--app/Template/dashboard/tasks.php38
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 ?>