summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric Guillot <fguillot@users.noreply.github.com>2014-03-16 10:44:05 -0400
committerFrédéric Guillot <fguillot@users.noreply.github.com>2014-03-16 10:44:05 -0400
commite0a5045ed5f3a4a6a34d252f5251295a27d11418 (patch)
treefb9affe5aab371e64ceb6403818d6acd99203b97
parent395a8a5f2a4976b80432a0d71d51d1bad3d01a83 (diff)
Add the possiblity to reorder the column position for a board
-rw-r--r--assets/css/app.css2
-rw-r--r--controllers/board.php104
-rw-r--r--locales/fr_FR/translations.php4
-rw-r--r--locales/pl_PL/translations.php6
-rw-r--r--models/action.php6
-rw-r--r--models/board.php182
-rw-r--r--templates/board_edit.php39
-rw-r--r--tests/BoardTest.php77
8 files changed, 384 insertions, 36 deletions
diff --git a/assets/css/app.css b/assets/css/app.css
index 274c11a3..df4beb18 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -145,7 +145,7 @@ textarea:focus {
}
input[type="number"] {
- width: 50px;
+ width: 70px;
}
textarea {
diff --git a/controllers/board.php b/controllers/board.php
index b07ca61c..941e987b 100644
--- a/controllers/board.php
+++ b/controllers/board.php
@@ -4,9 +4,49 @@ namespace Controller;
require_once __DIR__.'/base.php';
+/**
+ * Board controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
class Board extends Base
{
- // Change a task assignee directly from the board
+ /**
+ * Move a column up
+ *
+ * @access public
+ */
+ public function moveUp()
+ {
+ $project_id = $this->request->getIntegerParam('project_id');
+ $column_id = $this->request->getIntegerParam('column_id');
+
+ $this->board->moveUp($project_id, $column_id);
+
+ $this->response->redirect('?controller=board&action=edit&project_id='.$project_id);
+ }
+
+ /**
+ * Move a column down
+ *
+ * @access public
+ */
+ public function moveDown()
+ {
+ $project_id = $this->request->getIntegerParam('project_id');
+ $column_id = $this->request->getIntegerParam('column_id');
+
+ $this->board->moveDown($project_id, $column_id);
+
+ $this->response->redirect('?controller=board&action=edit&project_id='.$project_id);
+ }
+
+ /**
+ * Change a task assignee directly from the board
+ *
+ * @access public
+ */
public function assign()
{
$task = $this->task->getById($this->request->getIntegerParam('task_id'));
@@ -32,7 +72,11 @@ class Board extends Base
)));
}
- // Validate an assignee change
+ /**
+ * Validate an assignee modification
+ *
+ * @access public
+ */
public function assignTask()
{
$values = $this->request->getValues();
@@ -50,8 +94,12 @@ class Board extends Base
$this->response->redirect('?controller=board&action=show&project_id='.$values['project_id']);
}
- // Display the public version of a board
- // Access checked by a simple token, no user login, read only, auto-refresh
+ /**
+ * Display the public version of a board
+ * Access checked by a simple token, no user login, read only, auto-refresh
+ *
+ * @access public
+ */
public function readonly()
{
$token = $this->request->getStringParam('token');
@@ -72,7 +120,11 @@ class Board extends Base
)));
}
- // Display the default user project or the first project
+ /**
+ * Display the default user project or the first project
+ *
+ * @access public
+ */
public function index()
{
$projects = $this->project->getListByStatus(\Model\Project::ACTIVE);
@@ -110,7 +162,11 @@ class Board extends Base
)));
}
- // Show a board for a given project
+ /**
+ * Show a board for a given project
+ *
+ * @access public
+ */
public function show()
{
$projects = $this->project->getListByStatus(\Model\Project::ACTIVE);
@@ -136,7 +192,11 @@ class Board extends Base
)));
}
- // Display a form to edit a board
+ /**
+ * Display a form to edit a board
+ *
+ * @access public
+ */
public function edit()
{
$project_id = $this->request->getIntegerParam('project_id');
@@ -162,7 +222,11 @@ class Board extends Base
)));
}
- // Validate and update a board
+ /**
+ * Validate and update a board
+ *
+ * @access public
+ */
public function update()
{
$project_id = $this->request->getIntegerParam('project_id');
@@ -203,7 +267,11 @@ class Board extends Base
)));
}
- // Validate and add a new column
+ /**
+ * Validate and add a new column
+ *
+ * @access public
+ */
public function add()
{
$project_id = $this->request->getIntegerParam('project_id');
@@ -242,7 +310,11 @@ class Board extends Base
)));
}
- // Confirmation dialog before removing a column
+ /**
+ * Confirmation dialog before removing a column
+ *
+ * @access public
+ */
public function confirm()
{
$this->response->html($this->template->layout('board_remove', array(
@@ -252,7 +324,11 @@ class Board extends Base
)));
}
- // Remove a column
+ /**
+ * Remove a column
+ *
+ * @access public
+ */
public function remove()
{
$column = $this->board->getColumn($this->request->getIntegerParam('column_id'));
@@ -266,7 +342,11 @@ class Board extends Base
$this->response->redirect('?controller=board&action=edit&project_id='.$column['project_id']);
}
- // Save the board (Ajax request made by the drag and drop)
+ /**
+ * Save the board (Ajax request made by the drag and drop)
+ *
+ * @access public
+ */
public function save()
{
$project_id = $this->request->getIntegerParam('project_id');
diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php
index 690ce3fa..3b84029e 100644
--- a/locales/fr_FR/translations.php
+++ b/locales/fr_FR/translations.php
@@ -248,4 +248,8 @@ return array(
'Open a closed task' => 'Ouverture d\'une tâche fermée',
'Closing a task' => 'Fermeture d\'une tâche',
'Assign a color to a specific user' => 'Assigner une couleur à un utilisateur',
+ 'Column title' => 'Titre de la colonne',
+ 'Position' => 'Position',
+ 'Move Up' => 'Déplacer vers le haut',
+ 'Move Down' => 'Déplacer vers le bas',
);
diff --git a/locales/pl_PL/translations.php b/locales/pl_PL/translations.php
index ffc078a9..458ad25d 100644
--- a/locales/pl_PL/translations.php
+++ b/locales/pl_PL/translations.php
@@ -216,7 +216,7 @@ return array(
'The description is required' => 'Opis jest wymagany',
'Edit this task' => 'Edytuj zadanie',
'Due Date' => 'Termin',
- 'm/d/Y' => 'd/m/Y', // Date format parsed with php
+ 'm/d/Y' => 'd/m/Y', // Date format parsed with php
'month/day/year' => 'dzień/miesiąc/rok', // Help shown to the user
'Invalid date' => 'Błędna data',
'Must be done before %B %e, %G' => 'Termin do %e %B %G',
@@ -251,4 +251,8 @@ return array(
'Open a closed task' => 'Otwarcie zamkniętego zadania',
'Closing a task' => 'Zamknięcie zadania',
'Assign a color to a specific user' => 'Przypisz kolor do wybranego użytkownika',
+ // 'Column title' => '',
+ // 'Position' => '',
+ // 'Move Up' => '',
+ // 'Move Down' => '',
);
diff --git a/models/action.php b/models/action.php
index f3e2094d..cc8f5cad 100644
--- a/models/action.php
+++ b/models/action.php
@@ -8,6 +8,12 @@ require_once __DIR__.'/task.php';
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
+/**
+ * Action model
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
class Action extends Base
{
const TABLE = 'actions';
diff --git a/models/board.php b/models/board.php
index 2835f02f..ae306508 100644
--- a/models/board.php
+++ b/models/board.php
@@ -8,11 +8,23 @@ require_once __DIR__.'/task.php';
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
+/**
+ * Board model
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
class Board extends Base
{
const TABLE = 'columns';
- // Save the board (each task position/column)
+ /**
+ * Save task positions for each column
+ *
+ * @access public
+ * @param array $values [['task_id' => X, 'column_id' => X, 'position' => X], ...]
+ * @return boolean
+ */
public function saveTasksPosition(array $values)
{
$this->db->startTransaction();
@@ -33,7 +45,14 @@ class Board extends Base
return ! in_array(false, $results, true);
}
- // Create board with default columns => must be executed inside a transaction
+ /**
+ * Create a board with default columns, must be executed inside a transaction
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @param array $columns List of columns title ['column1', 'column2', ...]
+ * @return boolean
+ */
public function create($project_id, array $columns)
{
$position = 0;
@@ -46,20 +65,34 @@ class Board extends Base
'project_id' => $project_id,
);
- $this->db->table(self::TABLE)->save($values);
+ if (! $this->db->table(self::TABLE)->save($values)) {
+ return false;
+ }
}
return true;
}
- // Add a new column to the board
+ /**
+ * Add a new column to the board
+ *
+ * @access public
+ * @param array $values ['title' => X, 'project_id' => X]
+ * @return boolean
+ */
public function add(array $values)
{
$values['position'] = $this->getLastColumnPosition($values['project_id']) + 1;
return $this->db->table(self::TABLE)->save($values);
}
- // Update columns
+ /**
+ * Update columns
+ *
+ * @access public
+ * @param array $values Form values
+ * @return boolean
+ */
public function update(array $values)
{
$this->db->startTransaction();
@@ -75,7 +108,71 @@ class Board extends Base
return true;
}
- // Get columns and tasks for each column
+ /**
+ * Move a column down, increment the column position value
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @param integer $column_id Column id
+ * @return boolean
+ */
+ public function moveDown($project_id, $column_id)
+ {
+ $columns = $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('position')->listing('id', 'position');
+ $positions = array_flip($columns);
+
+ if (isset($columns[$column_id]) && $columns[$column_id] < count($columns)) {
+
+ $position = ++$columns[$column_id];
+ $columns[$positions[$position]]--;
+
+ $this->db->startTransaction();
+ $this->db->table(self::TABLE)->eq('id', $column_id)->update(array('position' => $position));
+ $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $columns[$positions[$position]]));
+ $this->db->closeTransaction();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move a column up, decrement the column position value
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @param integer $column_id Column id
+ * @return boolean
+ */
+ public function moveUp($project_id, $column_id)
+ {
+ $columns = $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('position')->listing('id', 'position');
+ $positions = array_flip($columns);
+
+ if (isset($columns[$column_id]) && $columns[$column_id] > 1) {
+
+ $position = --$columns[$column_id];
+ $columns[$positions[$position]]++;
+
+ $this->db->startTransaction();
+ $this->db->table(self::TABLE)->eq('id', $column_id)->update(array('position' => $position));
+ $this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $columns[$positions[$position]]));
+ $this->db->closeTransaction();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get all columns and tasks for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return array
+ */
public function get($project_id)
{
$this->db->startTransaction();
@@ -92,37 +189,73 @@ class Board extends Base
return $columns;
}
- // Get first column id for a given project
+ /**
+ * Get the first column id for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return integer
+ */
public function getFirstColumn($project_id)
{
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('position')->findOneColumn('id');
}
- // Get list of columns
+ /**
+ * Get the list of columns sorted by position [ column_id => title ]
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return array
+ */
public function getColumnsList($project_id)
{
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('position')->listing('id', 'title');
}
- // Get all columns information for a project
+ /**
+ * Get all columns sorted by position for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return array
+ */
public function getColumns($project_id)
{
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->asc('position')->findAll();
}
- // Get the number of columns for a project
+ /**
+ * Get the number of columns for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return integer
+ */
public function countColumns($project_id)
{
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->count();
}
- // Get just one column
+ /**
+ * Get a column by the id
+ *
+ * @access public
+ * @param integer $column_id Column id
+ * @return array
+ */
public function getColumn($column_id)
{
return $this->db->table(self::TABLE)->eq('id', $column_id)->findOne();
}
- // Get the position of the last column for a project
+ /**
+ * Get the position of the last column for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return integer
+ */
public function getLastColumnPosition($project_id)
{
return (int) $this->db
@@ -132,13 +265,26 @@ class Board extends Base
->findOneColumn('position');
}
- // Remove a column and all tasks associated to this column
+ /**
+ * Remove a column and all tasks associated to this column
+ *
+ * @access public
+ * @param integer $column_id Column id
+ * @return boolean
+ */
public function removeColumn($column_id)
{
return $this->db->table(self::TABLE)->eq('id', $column_id)->remove();
}
- // Validate columns update
+ /**
+ * Validate column modification
+ *
+ * @access public
+ * @param array $columns Original columns List
+ * @param array $values Required parameters to update a column
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
public function validateModification(array $columns, array $values)
{
$rules = array();
@@ -158,7 +304,13 @@ class Board extends Base
);
}
- // Validate column creation
+ /**
+ * Validate column creation
+ *
+ * @access public
+ * @param array $values Required parameters to save an action
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
public function validateCreation(array $values)
{
$v = new Validator($values, array(
diff --git a/templates/board_edit.php b/templates/board_edit.php
index 5368dede..35589bb4 100644
--- a/templates/board_edit.php
+++ b/templates/board_edit.php
@@ -11,13 +11,38 @@
<form method="post" action="?controller=board&amp;action=update&amp;project_id=<?= $project['id'] ?>" autocomplete="off">
<?php $i = 0; ?>
-
- <?php foreach ($columns as $column): ?>
- <?= Helper\form_label(t('Column %d', ++$i), 'title['.$column['id'].']') ?>
- <?= Helper\form_text('title['.$column['id'].']', $values, $errors, array('required')) ?>
- <?= Helper\form_number('task_limit['.$column['id'].']', $values, $errors, array('placeholder="'.t('limit').'"')) ?>
- <a href="?controller=board&amp;action=confirm&amp;project_id=<?= $project['id'] ?>&amp;column_id=<?= $column['id'] ?>"><?= t('Remove') ?></a>
- <?php endforeach ?>
+ <table>
+ <tr>
+ <th><?= t('Position') ?></th>
+ <th><?= t('Column title') ?></th>
+ <th><?= t('Task limit') ?></th>
+ <th><?= t('Actions') ?></th>
+ </tr>
+ <?php foreach ($columns as $column): ?>
+ <tr>
+ <td><?= Helper\form_label(t('Column %d', ++$i), 'title['.$column['id'].']') ?></td>
+ <td><?= Helper\form_text('title['.$column['id'].']', $values, $errors, array('required')) ?></td>
+ <td><?= Helper\form_number('task_limit['.$column['id'].']', $values, $errors, array('placeholder="'.t('limit').'"')) ?></td>
+ <td>
+ <ul>
+ <?php if ($column['position'] != 1): ?>
+ <li>
+ <a href="?controller=board&amp;action=moveUp&amp;project_id=<?= $project['id'] ?>&amp;column_id=<?= $column['id'] ?>"><?= t('Move Up') ?></a>
+ </li>
+ <?php endif ?>
+ <?php if ($column['position'] != count($columns)): ?>
+ <li>
+ <a href="?controller=board&amp;action=moveDown&amp;project_id=<?= $project['id'] ?>&amp;column_id=<?= $column['id'] ?>"><?= t('Move Down') ?></a>
+ </li>
+ <?php endif ?>
+ <li>
+ <a href="?controller=board&amp;action=confirm&amp;project_id=<?= $project['id'] ?>&amp;column_id=<?= $column['id'] ?>"><?= t('Remove') ?></a>
+ </li>
+ </ul>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </table>
<div class="form-actions">
<input type="submit" value="<?= t('Update') ?>" class="btn btn-blue"/>
diff --git a/tests/BoardTest.php b/tests/BoardTest.php
new file mode 100644
index 00000000..c29b2d0c
--- /dev/null
+++ b/tests/BoardTest.php
@@ -0,0 +1,77 @@
+<?php
+
+require_once __DIR__.'/base.php';
+
+use Model\Project;
+use Model\Board;
+
+class BoardTest extends Base
+{
+ public function testMoveColumns()
+ {
+ $p = new Project($this->db, $this->event);
+ $b = new Board($this->db, $this->event);
+
+ // We create 2 projects
+ $this->assertEquals(1, $p->create(array('name' => 'UnitTest1')));
+ $this->assertEquals(2, $p->create(array('name' => 'UnitTest2')));
+
+ // We get the columns of the project 2
+ $columns = $b->getColumns(2);
+ $columns_id = array_keys($b->getColumnsList(2));
+ $this->assertNotEmpty($columns);
+
+ // Initial order: 5, 6, 7, 8
+
+ // Move the column 1 down
+ $this->assertEquals(1, $columns[0]['position']);
+ $this->assertEquals($columns_id[0], $columns[0]['id']);
+
+ $this->assertEquals(2, $columns[1]['position']);
+ $this->assertEquals($columns_id[1], $columns[1]['id']);
+
+ $this->assertTrue($b->moveDown(2, $columns[0]['id']));
+ $columns = $b->getColumns(2); // Sorted by position
+
+ // New order: 6, 5, 7, 8
+
+ $this->assertEquals(1, $columns[0]['position']);
+ $this->assertEquals($columns_id[1], $columns[0]['id']);
+
+ $this->assertEquals(2, $columns[1]['position']);
+ $this->assertEquals($columns_id[0], $columns[1]['id']);
+
+ // Move the column 3 up
+ $this->assertTrue($b->moveUp(2, $columns[2]['id']));
+ $columns = $b->getColumns(2);
+
+ // New order: 6, 7, 5, 8
+
+ $this->assertEquals(1, $columns[0]['position']);
+ $this->assertEquals($columns_id[1], $columns[0]['id']);
+
+ $this->assertEquals(2, $columns[1]['position']);
+ $this->assertEquals($columns_id[2], $columns[1]['id']);
+
+ $this->assertEquals(3, $columns[2]['position']);
+ $this->assertEquals($columns_id[0], $columns[2]['id']);
+
+ // Move column 1 up (must do nothing because it's the first column)
+ $this->assertFalse($b->moveUp(2, $columns[0]['id']));
+ $columns = $b->getColumns(2);
+
+ // Order: 6, 7, 5, 8
+
+ $this->assertEquals(1, $columns[0]['position']);
+ $this->assertEquals($columns_id[1], $columns[0]['id']);
+
+ // Move column 4 down (must do nothing because it's the last column)
+ $this->assertFalse($b->moveDown(2, $columns[3]['id']));
+ $columns = $b->getColumns(2);
+
+ // Order: 6, 7, 5, 8
+
+ $this->assertEquals(4, $columns[3]['position']);
+ $this->assertEquals($columns_id[3], $columns[3]['id']);
+ }
+}