summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2017-02-18 13:38:51 -0500
committerFrederic Guillot <fred@kanboard.net>2017-02-18 13:38:51 -0500
commit49c8e5c1be15b9732023703473bb7e15864770f6 (patch)
treea4dcf83e0601fd734d44ad67e36299921959c3c2
parent948b7fbaaa58c0a825938f7e8bda9a07ec39239b (diff)
Prevent people to remove swimlanes that contains tasks
-rw-r--r--ChangeLog6
-rw-r--r--app/Controller/ColumnController.php2
-rw-r--r--app/Controller/ProjectOverviewController.php2
-rw-r--r--app/Controller/ProjectViewController.php2
-rw-r--r--app/Controller/SwimlaneController.php5
-rw-r--r--app/Model/ColumnModel.php4
-rw-r--r--app/Model/ProjectModel.php2
-rw-r--r--app/Model/SwimlaneModel.php34
-rw-r--r--app/Template/column/index.php39
-rw-r--r--app/Template/swimlane/index.php2
-rw-r--r--app/Template/swimlane/table.php50
-rw-r--r--tests/units/Model/ColumnModelTest.php2
-rw-r--r--tests/units/Model/SwimlaneModelTest.php36
13 files changed, 132 insertions, 54 deletions
diff --git a/ChangeLog b/ChangeLog
index 7ab888c9..3524e419 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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()"
diff --git a/app/Controller/ColumnController.php b/app/Controller/ColumnController.php
index 3facbebc..7047d30e 100644
--- a/app/Controller/ColumnController.php
+++ b/app/Controller/ColumnController.php
@@ -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,
diff --git a/app/Controller/ProjectOverviewController.php b/app/Controller/ProjectOverviewController.php
index 33bec078..477c1dd5 100644
--- a/app/Controller/ProjectOverviewController.php
+++ b/app/Controller/ProjectOverviewController.php
@@ -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,
diff --git a/app/Controller/ProjectViewController.php b/app/Controller/ProjectViewController.php
index 8ccf36ab..8ff79343 100644
--- a/app/Controller/ProjectViewController.php
+++ b/app/Controller/ProjectViewController.php
@@ -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,
diff --git a/app/Controller/SwimlaneController.php b/app/Controller/SwimlaneController.php
index d99cfa7a..0d81d83c 100644
--- a/app/Controller/SwimlaneController.php
+++ b/app/Controller/SwimlaneController.php
@@ -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')
)));
diff --git a/app/Model/ColumnModel.php b/app/Model/ColumnModel.php
index da5ea856..05f76fb9 100644
--- a/app/Model/ColumnModel.php
+++ b/app/Model/ColumnModel.php
@@ -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')
diff --git a/app/Model/ProjectModel.php b/app/Model/ProjectModel.php
index a4d75a0b..b88a8c8b 100644
--- a/app/Model/ProjectModel.php
+++ b/app/Model/ProjectModel.php
@@ -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) {
diff --git a/app/Model/SwimlaneModel.php b/app/Model/SwimlaneModel.php
index 30012096..2b3be912 100644
--- a/app/Model/SwimlaneModel.php
+++ b/app/Model/SwimlaneModel.php
@@ -164,6 +164,40 @@ class SwimlaneModel extends Base
}
/**
+ * 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
*
* @access public
diff --git a/app/Template/column/index.php b/app/Template/column/index.php
index 6108661b..3c60d021 100644
--- a/app/Template/column/index.php
+++ b/app/Template/column/index.php
@@ -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>
diff --git a/app/Template/swimlane/index.php b/app/Template/swimlane/index.php
index 35bbb589..59133db3 100644
--- a/app/Template/swimlane/index.php
+++ b/app/Template/swimlane/index.php
@@ -23,6 +23,6 @@
<?= $this->render('swimlane/table', array(
'swimlanes' => $inactive_swimlanes,
'project' => $project,
- 'disable_handler' => true,
+ 'disable_handle' => true,
)) ?>
<?php endif ?>
diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php
index 4f87924d..708b67f5 100644
--- a/app/Template/swimlane/table.php
+++ b/app/Template/swimlane/table.php
@@ -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 ?>
diff --git a/tests/units/Model/ColumnModelTest.php b/tests/units/Model/ColumnModelTest.php
index 75d1da20..9f2a4d9e 100644
--- a/tests/units/Model/ColumnModelTest.php
+++ b/tests/units/Model/ColumnModelTest.php
@@ -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']);
diff --git a/tests/units/Model/SwimlaneModelTest.php b/tests/units/Model/SwimlaneModelTest.php
index 7da93f9c..6bcc3bbf 100644
--- a/tests/units/Model/SwimlaneModelTest.php
+++ b/tests/units/Model/SwimlaneModelTest.php
@@ -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']);
+ }
}