diff options
author | Frederic Guillot <fred@kanboard.net> | 2017-02-26 19:30:02 -0500 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2017-02-26 19:30:02 -0500 |
commit | f3deb6492a74f1ffa9e3391274e0ab7947a04016 (patch) | |
tree | cbf7a3563cf1543bd131dd114f8dc89afdf5328f /app | |
parent | 4f325193be4f16a9658258fecd525e71917156a0 (diff) |
Add toggle button to show/hide subtasks in task list view
Diffstat (limited to 'app')
-rw-r--r-- | app/Controller/SubtaskStatusController.php | 37 | ||||
-rw-r--r-- | app/Controller/TaskListController.php | 14 | ||||
-rw-r--r-- | app/Core/Base.php | 1 | ||||
-rw-r--r-- | app/Core/Session/SessionStorage.php | 2 | ||||
-rw-r--r-- | app/Core/User/UserSession.php | 11 | ||||
-rw-r--r-- | app/Formatter/BoardFormatter.php | 2 | ||||
-rw-r--r-- | app/Formatter/SubtaskListFormatter.php | 2 | ||||
-rw-r--r-- | app/Formatter/TaskListFormatter.php | 4 | ||||
-rw-r--r-- | app/Formatter/TaskListSubtaskFormatter.php | 29 | ||||
-rw-r--r-- | app/Helper/SubtaskHelper.php | 59 | ||||
-rw-r--r-- | app/Helper/UserHelper.php | 13 | ||||
-rw-r--r-- | app/Model/SubtaskModel.php | 17 | ||||
-rw-r--r-- | app/Model/TaskTagModel.php | 3 | ||||
-rw-r--r-- | app/ServiceProvider/FormatterProvider.php | 1 | ||||
-rw-r--r-- | app/Template/board/tooltip_subtasks.php | 2 | ||||
-rw-r--r-- | app/Template/dashboard/subtasks.php | 2 | ||||
-rw-r--r-- | app/Template/subtask/table.php | 24 | ||||
-rw-r--r-- | app/Template/subtask/timer.php | 13 | ||||
-rw-r--r-- | app/Template/task_list/header.php | 6 | ||||
-rw-r--r-- | app/Template/task_list/listing.php | 13 | ||||
-rw-r--r-- | app/Template/task_list/task_subtasks.php | 22 |
21 files changed, 207 insertions, 70 deletions
diff --git a/app/Controller/SubtaskStatusController.php b/app/Controller/SubtaskStatusController.php index d4d356c3..72feb685 100644 --- a/app/Controller/SubtaskStatusController.php +++ b/app/Controller/SubtaskStatusController.php @@ -21,15 +21,9 @@ class SubtaskStatusController extends BaseController $subtask = $this->getSubtask(); $status = $this->subtaskStatusModel->toggleStatus($subtask['id']); + $subtask['status'] = $status; - if ($this->request->getIntegerParam('refresh-table') === 0) { - $subtask['status'] = $status; - $html = $this->helper->subtask->toggleStatus($subtask, $task['project_id']); - } else { - $html = $this->renderTable($task); - } - - $this->response->html($html); + $this->response->html($this->helper->subtask->renderToggleStatus($task, $subtask)); } /** @@ -40,32 +34,19 @@ class SubtaskStatusController extends BaseController public function timer() { $task = $this->getTask(); - $subtask_id = $this->request->getIntegerParam('subtask_id'); + $subtaskId = $this->request->getIntegerParam('subtask_id'); $timer = $this->request->getStringParam('timer'); if ($timer === 'start') { - $this->subtaskTimeTrackingModel->logStartTime($subtask_id, $this->userSession->getId()); + $this->subtaskTimeTrackingModel->logStartTime($subtaskId, $this->userSession->getId()); } elseif ($timer === 'stop') { - $this->subtaskTimeTrackingModel->logEndTime($subtask_id, $this->userSession->getId()); + $this->subtaskTimeTrackingModel->logEndTime($subtaskId, $this->userSession->getId()); $this->subtaskTimeTrackingModel->updateTaskTimeTracking($task['id']); } - $this->response->html($this->renderTable($task)); - } - - /** - * Render table - * - * @access private - * @param array $task - * @return string - */ - private function renderTable(array $task) - { - return $this->template->render('subtask/table', array( - 'task' => $task, - 'subtasks' => $this->subtaskModel->getAll($task['id']), - 'editable' => true, - )); + $this->response->html($this->template->render('subtask/timer', array( + 'task' => $task, + 'subtask' => $this->subtaskModel->getByIdWithDetails($subtaskId), + ))); } } diff --git a/app/Controller/TaskListController.php b/app/Controller/TaskListController.php index b3709a18..f2f2f6e5 100644 --- a/app/Controller/TaskListController.php +++ b/app/Controller/TaskListController.php @@ -23,12 +23,24 @@ class TaskListController extends BaseController $project = $this->getProject(); $search = $this->helper->projectHeader->getSearchQuery($project); + if ($this->request->getIntegerParam('show_subtasks')) { + $this->sessionStorage->subtaskListToggle = true; + } elseif ($this->request->getIntegerParam('hide_subtasks')) { + $this->sessionStorage->subtaskListToggle = false; + } + + if ($this->userSession->hasSubtaskListActivated()) { + $formatter = $this->taskListSubtaskFormatter; + } else { + $formatter = $this->taskListFormatter; + } + $paginator = $this->paginator ->setUrl('TaskListController', 'show', array('project_id' => $project['id'])) ->setMax(30) ->setOrder(TaskModel::TABLE.'.id') ->setDirection('DESC') - ->setFormatter($this->taskListFormatter) + ->setFormatter($formatter) ->setQuery($this->taskLexer ->build($search) ->withFilter(new TaskProjectFilter($project['id'])) diff --git a/app/Core/Base.php b/app/Core/Base.php index 8ef34bfb..28bbd534 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -76,6 +76,7 @@ use Pimple\Container; * @property \Kanboard\Formatter\TaskGanttFormatter $taskGanttFormatter * @property \Kanboard\Formatter\TaskICalFormatter $taskICalFormatter * @property \Kanboard\Formatter\TaskListFormatter $taskListFormatter + * @property \Kanboard\Formatter\TaskListSubtaskFormatter $taskListSubtaskFormatter * @property \Kanboard\Formatter\TaskSuggestMenuFormatter $taskSuggestMenuFormatter * @property \Kanboard\Formatter\UserAutoCompleteFormatter $userAutoCompleteFormatter * @property \Kanboard\Formatter\UserMentionFormatter $userMentionFormatter diff --git a/app/Core/Session/SessionStorage.php b/app/Core/Session/SessionStorage.php index e6478d8d..bb6771f1 100644 --- a/app/Core/Session/SessionStorage.php +++ b/app/Core/Session/SessionStorage.php @@ -18,7 +18,7 @@ namespace Kanboard\Core\Session; * @property string $commentSorting * @property bool $hasSubtaskInProgress * @property bool $hasRememberMe - * @property bool $boardCollapsed + * @property bool $subtaskListToggle * @property string $scope * @property bool $twoFactorBeforeCodeCalled * @property string $twoFactorSecret diff --git a/app/Core/User/UserSession.php b/app/Core/User/UserSession.php index 7917b223..f3f7359a 100644 --- a/app/Core/User/UserSession.php +++ b/app/Core/User/UserSession.php @@ -146,6 +146,17 @@ class UserSession extends Base } /** + * Return true if subtask list toggle is active + * + * @access public + * @return string + */ + public function hasSubtaskListActivated() + { + return isset($this->sessionStorage->subtaskListToggle) && ! empty($this->sessionStorage->subtaskListToggle); + } + + /** * Check is the user is connected * * @access public diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php index 59a8fb18..a43790b0 100644 --- a/app/Formatter/BoardFormatter.php +++ b/app/Formatter/BoardFormatter.php @@ -58,7 +58,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface ->findAll(); $task_ids = array_column($tasks, 'id'); - $tags = $this->taskTagModel->getTagsByTasks($task_ids); + $tags = $this->taskTagModel->getTagsByTaskIds($task_ids); return $this->boardSwimlaneFormatter ->withSwimlanes($swimlanes) diff --git a/app/Formatter/SubtaskListFormatter.php b/app/Formatter/SubtaskListFormatter.php index 5b20111d..8af5b1f5 100644 --- a/app/Formatter/SubtaskListFormatter.php +++ b/app/Formatter/SubtaskListFormatter.php @@ -16,7 +16,7 @@ class SubtaskListFormatter extends BaseFormatter implements FormatterInterface * Apply formatter * * @access public - * @return mixed + * @return array */ public function format() { diff --git a/app/Formatter/TaskListFormatter.php b/app/Formatter/TaskListFormatter.php index 01fbbae0..2f83469d 100644 --- a/app/Formatter/TaskListFormatter.php +++ b/app/Formatter/TaskListFormatter.php @@ -16,13 +16,13 @@ class TaskListFormatter extends BaseFormatter implements FormatterInterface * Apply formatter * * @access public - * @return mixed + * @return array */ public function format() { $tasks = $this->query->findAll(); $taskIds = array_column($tasks, 'id'); - $tags = $this->taskTagModel->getTagsByTasks($taskIds); + $tags = $this->taskTagModel->getTagsByTaskIds($taskIds); array_merge_relation($tasks, $tags, 'tags', 'id'); return $tasks; diff --git a/app/Formatter/TaskListSubtaskFormatter.php b/app/Formatter/TaskListSubtaskFormatter.php new file mode 100644 index 00000000..4f889674 --- /dev/null +++ b/app/Formatter/TaskListSubtaskFormatter.php @@ -0,0 +1,29 @@ +<?php + +namespace Kanboard\Formatter; + +/** + * Class TaskListSubtaskFormatter + * + * @package Kanboard\Formatter + * @author Frederic Guillot + */ +class TaskListSubtaskFormatter extends TaskListFormatter +{ + /** + * Apply formatter + * + * @access public + * @return array + */ + public function format() + { + $tasks = parent::format(); + $taskIds = array_column($tasks, 'id'); + $subtasks = $this->subtaskModel->getAllByTaskIds($taskIds); + $subtasks = array_column_index($subtasks, 'task_id'); + array_merge_relation($tasks, $subtasks, 'subtasks', 'id'); + + return $tasks; + } +} diff --git a/app/Helper/SubtaskHelper.php b/app/Helper/SubtaskHelper.php index 1b8b0e51..eea1ed63 100644 --- a/app/Helper/SubtaskHelper.php +++ b/app/Helper/SubtaskHelper.php @@ -12,7 +12,23 @@ use Kanboard\Core\Base; */ class SubtaskHelper extends Base { - public function getTitle(array $subtask) + /** + * Return if the current user has a subtask in progress + * + * @return bool + */ + public function hasSubtaskInProgress() + { + return isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress; + } + + /** + * Render subtask title + * + * @param array $subtask + * @return string + */ + public function renderTitle(array $subtask) { if ($subtask['status'] == 0) { $html = '<i class="fa fa-square-o fa-fw"></i>'; @@ -29,25 +45,46 @@ class SubtaskHelper extends Base * Get the link to toggle subtask status * * @access public + * @param array $task * @param array $subtask - * @param integer $project_id - * @param boolean $refresh_table * @return string */ - public function toggleStatus(array $subtask, $project_id, $refresh_table = false) + public function renderToggleStatus(array $task, array $subtask) { - if (! $this->helper->user->hasProjectAccess('SubtaskController', 'edit', $project_id)) { - return $this->getTitle($subtask); + if (! $this->helper->user->hasProjectAccess('SubtaskController', 'edit', $task['project_id'])) { + $html = $this->renderTitle($subtask); + } else { + $title = $this->renderTitle($subtask); + $params = array( + 'project_id' => $task['project_id'], + 'task_id' => $subtask['task_id'], + 'subtask_id' => $subtask['id'], + ); + + if ($subtask['status'] == 0 && $this->hasSubtaskInProgress()) { + $html = $this->helper->url->link($title, 'SubtaskRestrictionController', 'show', $params, false, 'js-modal-confirm'); + } else { + $html = $this->helper->url->link($title, 'SubtaskStatusController', 'change', $params, false, 'js-subtask-toggle-status'); + } } - $params = array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'refresh-table' => (int) $refresh_table); + return '<span class="subtask-title">'.$html.'</span>'; + } + + public function renderTimer(array $task, array $subtask) + { + $html = '<span class="subtask-timer-toggle">'; - if ($subtask['status'] == 0 && isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress) { - return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestrictionController', 'show', $params, false, 'js-modal-confirm'); + if ($subtask['is_timer_started']) { + $html .= $this->helper->url->icon('pause', t('Stop timer'), 'SubtaskStatusController', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'js-subtask-toggle-timer'); + $html .= ' (' . $this->helper->dt->age($subtask['timer_start_date']) .')'; + } else { + $html .= $this->helper->url->icon('play-circle-o', t('Start timer'), 'SubtaskStatusController', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'js-subtask-toggle-timer'); } - $class = 'subtask-toggle-status '.($refresh_table ? 'subtask-refresh-table' : ''); - return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatusController', 'change', $params, false, $class); + $html .= '</span>'; + + return $html; } public function renderTitleField(array $values, array $errors = array(), array $attributes = array()) diff --git a/app/Helper/UserHelper.php b/app/Helper/UserHelper.php index 8c2567b9..02d1d451 100644 --- a/app/Helper/UserHelper.php +++ b/app/Helper/UserHelper.php @@ -13,7 +13,18 @@ use Kanboard\Core\Base; class UserHelper extends Base { /** - * Return true if the logged user as unread notifications + * Return subtask list toggle value + * + * @access public + * @return boolean + */ + public function hasSubtaskListActivated() + { + return $this->userSession->hasSubtaskListActivated(); + } + + /** + * Return true if the logged user has unread notifications * * @access public * @return boolean diff --git a/app/Model/SubtaskModel.php b/app/Model/SubtaskModel.php index af9af93b..c62ddb53 100644 --- a/app/Model/SubtaskModel.php +++ b/app/Model/SubtaskModel.php @@ -132,6 +132,23 @@ class SubtaskModel extends Base } /** + * Get subtasks for a list of tasks + * + * @param array $taskIds + * @return array + */ + public function getAllByTaskIds(array $taskIds) + { + if (empty($taskIds)) { + return array(); + } + + return $this->subtaskListFormatter + ->withQuery($this->getQuery()->in('task_id', $taskIds)) + ->format(); + } + + /** * Get a subtask by the id * * @access public diff --git a/app/Model/TaskTagModel.php b/app/Model/TaskTagModel.php index 0553cc6c..78b7a90a 100644 --- a/app/Model/TaskTagModel.php +++ b/app/Model/TaskTagModel.php @@ -59,7 +59,7 @@ class TaskTagModel extends Base * @param integer[] $task_ids * @return array */ - public function getTagsByTasks($task_ids) + public function getTagsByTaskIds($task_ids) { if (empty($task_ids)) { return array(); @@ -69,6 +69,7 @@ class TaskTagModel extends Base ->columns(TagModel::TABLE.'.id', TagModel::TABLE.'.name', self::TABLE.'.task_id') ->in(self::TABLE.'.task_id', $task_ids) ->join(self::TABLE, 'tag_id', 'id') + ->asc(TagModel::TABLE.'.name') ->findAll(); return array_column_index($tags, 'task_id'); diff --git a/app/ServiceProvider/FormatterProvider.php b/app/ServiceProvider/FormatterProvider.php index 54f9f916..feaa597f 100644 --- a/app/ServiceProvider/FormatterProvider.php +++ b/app/ServiceProvider/FormatterProvider.php @@ -30,6 +30,7 @@ class FormatterProvider implements ServiceProviderInterface 'TaskGanttFormatter', 'TaskICalFormatter', 'TaskListFormatter', + 'TaskListSubtaskFormatter', 'TaskSuggestMenuFormatter', 'UserAutoCompleteFormatter', 'UserMentionFormatter', diff --git a/app/Template/board/tooltip_subtasks.php b/app/Template/board/tooltip_subtasks.php index 335c28ce..753e4910 100644 --- a/app/Template/board/tooltip_subtasks.php +++ b/app/Template/board/tooltip_subtasks.php @@ -8,7 +8,7 @@ <?php foreach ($subtasks as $subtask): ?> <tr> <td> - <?= $this->subtask->toggleStatus($subtask, $task['project_id']) ?> + <?= $this->subtask->renderToggleStatus($task, $subtask) ?> </td> <?= $this->hook->render('template:board:tooltip:subtasks:rows', array('subtask' => $subtask)) ?> <td> diff --git a/app/Template/dashboard/subtasks.php b/app/Template/dashboard/subtasks.php index 13770f0f..d86b1ef9 100644 --- a/app/Template/dashboard/subtasks.php +++ b/app/Template/dashboard/subtasks.php @@ -25,7 +25,7 @@ <?= $this->url->link($this->text->e($subtask['task_name']), 'TaskViewController', 'show', array('task_id' => $subtask['task_id'], 'project_id' => $subtask['project_id'])) ?> </td> <td> - <?= $this->subtask->toggleStatus($subtask, $subtask['project_id']) ?> + <?= $this->subtask->renderToggleStatus(array('project_id' => $subtask['project_id']), $subtask) ?> </td> <?= $this->hook->render('template:dashboard:subtasks:rows', array('subtask' => $subtask)) ?> <td> diff --git a/app/Template/subtask/table.php b/app/Template/subtask/table.php index bfb42e75..5488796d 100644 --- a/app/Template/subtask/table.php +++ b/app/Template/subtask/table.php @@ -21,9 +21,9 @@ 'task' => $task, 'subtask' => $subtask, )) ?> - <?= $this->subtask->toggleStatus($subtask, $task['project_id'], true) ?> + <?= $this->subtask->renderToggleStatus($task, $subtask, true) ?> <?php else: ?> - <?= $this->subtask->getTitle($subtask) ?> + <?= $this->subtask->renderTitle($subtask) ?> <?php endif ?> </td> <td> @@ -33,22 +33,10 @@ </td> <?= $this->hook->render('template:subtask:table:rows', array('subtask' => $subtask)) ?> <td> - <?php if (! empty($subtask['time_spent'])): ?> - <strong><?= $this->text->e($subtask['time_spent']).'h' ?></strong> <?= t('spent') ?> - <?php endif ?> - - <?php if (! empty($subtask['time_estimated'])): ?> - <strong><?= $this->text->e($subtask['time_estimated']).'h' ?></strong> <?= t('estimated') ?> - <?php endif ?> - - <?php if ($editable && $subtask['user_id'] == $this->user->getId()): ?> - <?php if ($subtask['is_timer_started']): ?> - <?= $this->url->icon('pause', t('Stop timer'), 'SubtaskStatusController', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?> - (<?= $this->dt->age($subtask['timer_start_date']) ?>) - <?php else: ?> - <?= $this->url->icon('play-circle-o', t('Start timer'), 'SubtaskStatusController', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?> - <?php endif ?> - <?php endif ?> + <?= $this->render('subtask/timer', array( + 'task' => $task, + 'subtask' => $subtask, + )) ?> </td> </tr> <?php endforeach ?> diff --git a/app/Template/subtask/timer.php b/app/Template/subtask/timer.php new file mode 100644 index 00000000..2102e6cc --- /dev/null +++ b/app/Template/subtask/timer.php @@ -0,0 +1,13 @@ +<span class="subtask-time-tracking"> + <?php if (! empty($subtask['time_spent'])): ?> + <strong><?= $this->text->e($subtask['time_spent']).'h' ?></strong> <?= t('spent') ?> + <?php endif ?> + + <?php if (! empty($subtask['time_estimated'])): ?> + <strong><?= $this->text->e($subtask['time_estimated']).'h' ?></strong> <?= t('estimated') ?> + <?php endif ?> + + <?php if ($this->user->hasProjectAccess('SubtaskController', 'edit', $task['project_id']) && $subtask['user_id'] == $this->user->getId()): ?> + <?= $this->subtask->renderTimer($task, $subtask) ?> + <?php endif ?> +</span> diff --git a/app/Template/task_list/header.php b/app/Template/task_list/header.php index fb05dbdc..6501a919 100644 --- a/app/Template/task_list/header.php +++ b/app/Template/task_list/header.php @@ -7,6 +7,12 @@ <?php endif ?> </div> <div class="table-list-header-menu"> + <?php if ($this->user->hasSubtaskListActivated()): ?> + <?= $this->url->icon('tasks', t('Hide subtasks'), 'TaskListController', 'show', array('project_id' => $project['id'], 'hide_subtasks' => 1)) ?> + <?php else: ?> + <?= $this->url->icon('tasks', t('Show subtasks'), 'TaskListController', 'show', array('project_id' => $project['id'], 'show_subtasks' => 1)) ?> + <?php endif ?> + <?= $this->render('task_list/sort_menu', array('paginator' => $paginator)) ?> </div> </div>
\ No newline at end of file diff --git a/app/Template/task_list/listing.php b/app/Template/task_list/listing.php index 171c148d..b3c66aa6 100644 --- a/app/Template/task_list/listing.php +++ b/app/Template/task_list/listing.php @@ -5,7 +5,11 @@ <p class="alert"><?= t('No tasks found.') ?></p> <?php elseif (! $paginator->isEmpty()): ?> <div class="table-list"> - <?= $this->render('task_list/header', array('paginator' => $paginator)) ?> + <?= $this->render('task_list/header', array( + 'paginator' => $paginator, + 'project' => $project, + )) ?> + <?php foreach ($paginator->getCollection() as $task): ?> <div class="table-list-row color-<?= $task['color_id'] ?>"> <?= $this->render('task_list/task_title', array( @@ -21,8 +25,11 @@ )) ?> <?= $this->render('task_list/task_icons', array( - 'project' => $project, - 'task' => $task, + 'task' => $task, + )) ?> + + <?= $this->render('task_list/task_subtasks', array( + 'task' => $task, )) ?> </div> <?php endforeach ?> diff --git a/app/Template/task_list/task_subtasks.php b/app/Template/task_list/task_subtasks.php new file mode 100644 index 00000000..716d6df2 --- /dev/null +++ b/app/Template/task_list/task_subtasks.php @@ -0,0 +1,22 @@ +<?php if (! empty($task['subtasks'])): ?> +<div class="task-list-subtasks"> + <?php foreach ($task['subtasks'] as $subtask): ?> + <div class="task-list-subtask"> + <span class="subtask-cell column-50"> + <?= $this->subtask->renderToggleStatus($task, $subtask) ?> + </span> + <span class="subtask-cell column-20 subtask-assignee"> + <?php if (! empty($subtask['username'])): ?> + <?= $this->text->e($subtask['name'] ?: $subtask['username']) ?> + <?php endif ?> + </span> + <span class="subtask-cell subtask-time-tracking-cell"> + <?= $this->render('subtask/timer', array( + 'task' => $task, + 'subtask' => $subtask, + )) ?> + </span> + </div> + <?php endforeach ?> +</div> +<?php endif ?> |