Add checkboxes in list view to move tasks to another column at once

This commit is contained in:
Frédéric Guillot
2018-06-01 15:58:17 -07:00
parent cd6da13897
commit 912cf378d7
45 changed files with 344 additions and 4 deletions

View File

@@ -0,0 +1,44 @@
<?php
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
class TaskBulkMoveColumnController extends BaseController
{
public function show(array $values = [], array $errors = [])
{
$project = $this->getProject();
if (empty($values)) {
$values['task_ids'] = $this->request->getStringParam('task_ids');
}
$this->response->html($this->template->render('task_bulk_move_column/show', [
'project' => $project,
'values' => $values,
'errors' => $errors,
'columns' => $this->columnModel->getList($project['id']),
'swimlanes' => $this->swimlaneModel->getList($project['id'], false, true),
]));
}
public function save()
{
$project = $this->getProject();
$values = $this->request->getValues();
$taskIDs = explode(',', $values['task_ids']);
foreach ($taskIDs as $taskID) {
$task = $this->taskFinderModel->getById($taskID);
if (! $this->helper->projectRole->canMoveTask($task['project_id'], $task['column_id'], $values['column_id'])) {
throw new AccessForbiddenException(e('You are not allowed to move this task.'));
}
$this->taskPositionModel->moveBottom($project['id'], $taskID, $values['swimlane_id'], $values['column_id']);
}
$this->response->redirect($this->helper->url->to('TaskListController', 'show', ['project_id' => $project['id']]), true);
}
}

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s flyttet opgave #%d til spor "%s"',
'%sh spent' => '%sh brugt',
'%sh estimated' => '%sh anslået',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s a déplacé la tâche #%d vers la swimlane « %s »',
'%sh spent' => '%sh passé',
'%sh estimated' => '%sh estimé',
'Select All' => 'Tout sélectionner',
'Unselect All' => 'Tout désélectionner',
'Apply action' => 'Appliquer une action',
'Move selected tasks to another column' => 'Déplaçer les tâches sélectionnées vers une autre colonne',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s перенёс задачу #%d на дорожку "%s"',
'%sh spent' => '%sч затрачено',
'%sh estimated' => '%sч запланировано',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s , #%d görevini "%s" kulvarına taşıdı',
'%sh spent' => '%sh harcandı',
'%sh estimated' => '%sh tahmin edildi',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s перемістив задачу #%d на доріжку "%s"',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
'%s moved the task #%d to the swimlane "%s"' => '%s将任务 #%d 移动到了里程碑 "%s" 下',
'%sh spent' => '花费%s小时',
'%sh estimated' => '预估%s小时',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -1377,4 +1377,8 @@ return array(
// '%s moved the task #%d to the swimlane "%s"' => '',
// '%sh spent' => '',
// '%sh estimated' => '',
// 'Select All' => '',
// 'Unselect All' => '',
// 'Apply action' => '',
// 'Move selected tasks to another column' => '',
);

View File

@@ -12,6 +12,42 @@ use Kanboard\Core\Base;
*/
class TaskPositionModel extends Base
{
public function moveBottom($project_id, $task_id, $swimlane_id, $column_id)
{
$this->db->startTransaction();
$task = $this->taskFinderModel->getById($task_id);
$result = $this->db->table(TaskModel::TABLE)
->eq('project_id', $project_id)
->eq('swimlane_id', $swimlane_id)
->eq('column_id', $column_id)
->columns('MAX(position) AS pos')
->findOne();
$position = 1;
if (! empty($result)) {
$position = $result['pos'] + 1;
}
$result = $this->db->table(TaskModel::TABLE)
->eq('id', $task_id)
->eq('project_id', $project_id)
->update([
'swimlane_id' => $swimlane_id,
'column_id' => $column_id,
'position' => $position
]);
$this->db->closeTransaction();
if ($result) {
$this->fireEvents($task, $column_id, $position, $swimlane_id);
}
return $result;
}
/**
* Move a task to another column or to another position
*

View File

@@ -106,6 +106,7 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('TaskSuppressionController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskCreationController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskBulkController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskBulkMoveColumnController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskDuplicationController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskRecurrenceController', '*', Role::PROJECT_MEMBER);
$acl->add('TaskImportController', '*', Role::PROJECT_MANAGER);

View File

@@ -0,0 +1,16 @@
<div class="page-header">
<h2><?= t('Move selected tasks to another column') ?></h2>
</div>
<form action="<?= $this->url->href('TaskBulkMoveColumnController', 'save', ['project_id' => $project['id']]) ?>" method="post">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_ids', $values) ?>
<?= $this->form->label(t('Swimlane'), 'swimlane_id') ?>
<?= $this->form->select('swimlane_id', $swimlanes, $values) ?>
<?= $this->form->label(t('Column'), 'column_id') ?>
<?= $this->form->select('column_id', $columns, $values) ?>
<?= $this->modal->submitButtons() ?>
</form>

View File

@@ -6,6 +6,24 @@
<?= t('%d task', $paginator->getTotal()) ?>
<?php endif ?>
</div>
<?php if (isset($show_items_selection)): ?>
<?php if ($this->user->hasProjectAccess('TaskModificationController', 'save', $project['id'])): ?>
<div class="list-item-links">
<a href="#" data-list-item-selection="all"><?= t('Select All') ?></a> / <a href="#" data-list-item-selection="none"><?= t('Unselect All') ?></a>
</div>
<div class="list-item-actions list-item-action-hidden">
-&nbsp;
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><strong><?= t('Apply action') ?> <i class="fa fa-caret-down"></i></strong></a>
<ul>
<li>
<a href="<?= $this->url->href('TaskBulkMoveColumnController', 'show', ['project_id' => $project['id']]) ?>" data-list-item-action="modal"><?= t('Move selected tasks to another column') ?></a>
</li>
</ul>
</div>
</div>
<?php endif ?>
<?php endif ?>
<div class="table-list-header-menu">
<?php if (isset($project)): ?>
<?php if ($this->user->hasSubtaskListActivated()): ?>

View File

@@ -7,12 +7,14 @@
<?= $this->render('task_list/header', array(
'paginator' => $paginator,
'project' => $project,
'show_items_selection' => true,
)) ?>
<?php foreach ($paginator->getCollection() as $task): ?>
<div class="table-list-row color-<?= $task['color_id'] ?>">
<?= $this->render('task_list/task_title', array(
'task' => $task,
'show_items_selection' => true,
)) ?>
<?= $this->render('task_list/task_details', array(

View File

@@ -1,5 +1,8 @@
<div>
<?php if ($this->user->hasProjectAccess('TaskModificationController', 'edit', $task['project_id'])): ?>
<?php if (isset($show_items_selection)): ?>
<input type="checkbox" data-list-item="selectable" name="tasks[]" value="<?= $task['id'] ?>">
<?php endif ?>
<?= $this->render('task/dropdown', array('task' => $task)) ?>
<?php else: ?>
<strong><?= '#'.$task['id'] ?></strong>