Prevent people to remove swimlanes that contains tasks

This commit is contained in:
Frederic Guillot 2017-02-18 13:38:51 -05:00
parent 948b7fbaaa
commit 49c8e5c1be
13 changed files with 132 additions and 54 deletions

View File

@ -7,12 +7,14 @@ New features:
Improvements:
* Prevent people to remove swimlanes that contains tasks
* Show task count in swimlane table
* Use contextual menu instead of action column in users management
Breaking changes:
* The concept of "default swimlane" is removed
* Previous default swimlanes are migrated to an independent swimlane
* The concept of "default swimlane" has been removed
* Previous default swimlanes are migrated to an independent swimlanes
* Columns "default_swimlane" and "show_default_swimlane" from "projects" table are not used anymore
* Remove API method "getDefaultSwimlane()"
* Add mandatory argument "project_id" to API method "updateSwimlane()"

View File

@ -20,7 +20,7 @@ class ColumnController extends BaseController
public function index()
{
$project = $this->getProject();
$columns = $this->columnModel->getAllWithTasksCount($project['id']);
$columns = $this->columnModel->getAllWithTaskCount($project['id']);
$this->response->html($this->helper->layout->project('column/index', array(
'columns' => $columns,

View File

@ -16,7 +16,7 @@ class ProjectOverviewController extends BaseController
public function show()
{
$project = $this->getProject();
$columns = $this->columnModel->getAllWithTasksCount($project['id']);
$columns = $this->columnModel->getAllWithTaskCount($project['id']);
$this->response->html($this->helper->layout->app('project_overview/show', array(
'project' => $project,

View File

@ -18,7 +18,7 @@ class ProjectViewController extends BaseController
public function show()
{
$project = $this->getProject();
$columns = $this->columnModel->getAllWithTasksCount($project['id']);
$columns = $this->columnModel->getAllWithTaskCount($project['id']);
$this->response->html($this->helper->layout->project('project_view/show', array(
'project' => $project,

View File

@ -40,10 +40,11 @@ class SwimlaneController extends BaseController
public function index()
{
$project = $this->getProject();
$swimlanes = $this->swimlaneModel->getAllWithTaskCount($project['id']);
$this->response->html($this->helper->layout->project('swimlane/index', array(
'active_swimlanes' => $this->swimlaneModel->getAllByStatus($project['id'], SwimlaneModel::ACTIVE),
'inactive_swimlanes' => $this->swimlaneModel->getAllByStatus($project['id'], SwimlaneModel::INACTIVE),
'active_swimlanes' => $swimlanes['active'],
'inactive_swimlanes' => $swimlanes['inactive'],
'project' => $project,
'title' => t('Swimlanes')
)));

View File

@ -121,13 +121,13 @@ class ColumnModel extends Base
}
/**
* Get all columns with tasks count
* Get all columns with task count
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAllWithTasksCount($project_id)
public function getAllWithTaskCount($project_id)
{
return $this->db->table(self::TABLE)
->columns('id', 'title', 'position', 'task_limit', 'description', 'hide_in_dashboard', 'project_id')

View File

@ -270,7 +270,7 @@ class ProjectModel extends Base
*/
public function getColumnStats(array &$project)
{
$project['columns'] = $this->columnModel->getAllWithTasksCount($project['id']);
$project['columns'] = $this->columnModel->getAllWithTaskCount($project['id']);
$project['nb_active_tasks'] = 0;
foreach ($project['columns'] as $column) {

View File

@ -163,6 +163,40 @@ class SwimlaneModel extends Base
return $query->findAll();
}
/**
* Get all swimlanes with task count
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAllWithTaskCount($project_id)
{
$result = array(
'active' => array(),
'inactive' => array(),
);
$swimlanes = $this->db->table(self::TABLE)
->columns('id', 'name', 'description', 'project_id', 'position', 'is_active')
->subquery("SELECT COUNT(*) FROM ".TaskModel::TABLE." WHERE swimlane_id=".self::TABLE.".id AND is_active='1'", 'nb_open_tasks')
->subquery("SELECT COUNT(*) FROM ".TaskModel::TABLE." WHERE swimlane_id=".self::TABLE.".id AND is_active='0'", 'nb_closed_tasks')
->eq('project_id', $project_id)
->asc('position')
->asc('name')
->findAll();
foreach ($swimlanes as $swimlane) {
if ($swimlane['is_active']) {
$result['active'][] = $swimlane;
} else {
$result['inactive'][] = $swimlane;
}
}
return $result;
}
/**
* Get list of all swimlanes
*

View File

@ -15,19 +15,31 @@
data-save-position-url="<?= $this->url->href('ColumnController', 'move', array('project_id' => $project['id'])) ?>">
<thead>
<tr>
<th class="column-40"><?= t('Column') ?></th>
<th><?= t('Column') ?></th>
<th class="column-10"><?= t('Task limit') ?></th>
<th class="column-20"><?= t('Visible on dashboard') ?></th>
<th class="column-10"><?= t('Open tasks') ?></th>
<th class="column-10"><?= t('Closed tasks') ?></th>
<th><?= t('Actions') ?></th>
<th class="column-15"><?= t('Visible on dashboard') ?></th>
<th class="column-12"><?= t('Open tasks') ?></th>
<th class="column-12"><?= t('Closed tasks') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($columns as $column): ?>
<tr data-column-id="<?= $column['id'] ?>">
<td>
<i class="fa fa-arrows-alt draggable-row-handle" title="<?= t('Change column position') ?>"></i>
<i class="fa fa-arrows-alt draggable-row-handle" title="<?= t('Change column position') ?>"></i>&nbsp;
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
<?= $this->modal->medium('edit', t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
<?php if ($column['nb_open_tasks'] == 0 && $column['nb_closed_tasks'] == 0): ?>
<li>
<?= $this->modal->confirm('trash-o', t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
<?php endif ?>
</ul>
</div>
<?= $this->text->e($column['title']) ?>
<?php if (! empty($column['description'])): ?>
<span class="tooltip" title="<?= $this->text->markdownAttribute($column['description']) ?>">
@ -47,21 +59,6 @@
<td>
<?= $column['nb_closed_tasks'] ?>
</td>
<td>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
<?= $this->modal->medium('edit', t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
<?php if ($column['nb_open_tasks'] == 0 && $column['nb_closed_tasks'] == 0): ?>
<li>
<?= $this->modal->confirm('trash-o', t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
<?php endif ?>
</ul>
</div>
</td>
</tr>
<?php endforeach ?>
</tbody>

View File

@ -23,6 +23,6 @@
<?= $this->render('swimlane/table', array(
'swimlanes' => $inactive_swimlanes,
'project' => $project,
'disable_handler' => true,
'disable_handle' => true,
)) ?>
<?php endif ?>

View File

@ -4,17 +4,39 @@
<thead>
<tr>
<th><?= t('Name') ?></th>
<th class="column-8"><?= t('Actions') ?></th>
<th class="column-15"><?= t('Open tasks') ?></th>
<th class="column-15"><?= t('Closed tasks') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($swimlanes as $swimlane): ?>
<tr data-swimlane-id="<?= $swimlane['id'] ?>">
<td>
<?php if (! isset($disable_handler)): ?>
<i class="fa fa-arrows-alt draggable-row-handle" title="<?= t('Change column position') ?>"></i>
<?php if (! isset($disable_handle)): ?>
<i class="fa fa-arrows-alt draggable-row-handle" title="<?= t('Change column position') ?>"></i>&nbsp;
<?php endif ?>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
<?= $this->modal->medium('edit', t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<li>
<?php if ($swimlane['is_active']): ?>
<?= $this->url->icon('toggle-off', t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php else: ?>
<?= $this->url->icon('toggle-on', t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php endif ?>
</li>
<?php if ($swimlane['nb_open_tasks'] == 0 && $swimlane['nb_closed_tasks'] == 0): ?>
<li>
<?= $this->modal->confirm('trash-o', t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<?php endif ?>
</ul>
</div>
<?= $this->text->e($swimlane['name']) ?>
<?php if (! empty($swimlane['description'])): ?>
@ -24,24 +46,10 @@
<?php endif ?>
</td>
<td>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
<?= $this->modal->medium('edit', t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<li>
<?php if ($swimlane['is_active']): ?>
<?= $this->url->icon('toggle-off', t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php else: ?>
<?= $this->url->icon('toggle-on', t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php endif ?>
</li>
<li>
<?= $this->modal->confirm('trash-o', t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
</ul>
</div>
<?= $swimlane['nb_open_tasks'] ?>
</td>
<td>
<?= $swimlane['nb_closed_tasks'] ?>
</td>
</tr>
<?php endforeach ?>

View File

@ -105,7 +105,7 @@ class ColumnModelTest extends Base
$this->assertEquals(1, $taskCreationModel->create(array('title' => 'UnitTest', 'project_id' => 1, 'column_id' => 1)));
$this->assertEquals(2, $taskCreationModel->create(array('title' => 'UnitTest', 'project_id' => 1, 'column_id' => 2, 'is_active' => 0)));
$columns = $columnModel->getAllWithTasksCount(1);
$columns = $columnModel->getAllWithTaskCount(1);
$this->assertCount(4, $columns);
$this->assertEquals(1, $columns[0]['id']);

View File

@ -324,4 +324,40 @@ class SwimlaneModelTest extends Base
$this->assertEquals(2, $swimlanes[1]['position']);
$this->assertEquals(1, $swimlanes[1]['id']);
}
public function testGetAllWithTaskCount()
{
$projectModel = new ProjectModel($this->container);
$swimlaneModel = new SwimlaneModel($this->container);
$taskCreationModel = new TaskCreationModel($this->container);
$this->assertEquals(1, $projectModel->create(array('name' => 'Project #1')));
$this->assertEquals(2, $swimlaneModel->create(1, 'Swimlane #1'));
$this->assertEquals(3, $swimlaneModel->create(1, 'Swimlane #2'));
$this->assertEquals(4, $swimlaneModel->create(1, 'Swimlane #3'));
$this->assertEquals(5, $swimlaneModel->create(1, 'Swimlane #4'));
$this->assertEquals(1, $taskCreationModel->create(array('title' => 'Task #1', 'project_id' => 1, 'swimlane_id' => 2)));
$this->assertEquals(2, $taskCreationModel->create(array('title' => 'Task #1', 'project_id' => 1, 'swimlane_id' => 3, 'is_active' => 0)));
$this->assertTrue($swimlaneModel->disable(1, 2));
$this->assertTrue($swimlaneModel->disable(1, 4));
$swimlanes = $swimlaneModel->getAllWithTaskCount(1);
$this->assertCount(3, $swimlanes['active']);
$this->assertCount(2, $swimlanes['inactive']);
$this->assertEquals('Default swimlane', $swimlanes['active'][0]['name']);
$this->assertEquals('Swimlane #2', $swimlanes['active'][1]['name']);
$this->assertEquals('Swimlane #4', $swimlanes['active'][2]['name']);
$this->assertEquals(0, $swimlanes['active'][1]['nb_open_tasks']);
$this->assertEquals(1, $swimlanes['active'][1]['nb_closed_tasks']);
$this->assertEquals('Swimlane #1', $swimlanes['inactive'][0]['name']);
$this->assertEquals('Swimlane #3', $swimlanes['inactive'][1]['name']);
$this->assertEquals(1, $swimlanes['inactive'][0]['nb_open_tasks']);
$this->assertEquals(0, $swimlanes['inactive'][0]['nb_closed_tasks']);
}
}