diff options
author | Frédéric Guillot <fguillot@users.noreply.github.com> | 2014-03-16 10:44:05 -0400 |
---|---|---|
committer | Frédéric Guillot <fguillot@users.noreply.github.com> | 2014-03-16 10:44:05 -0400 |
commit | e0a5045ed5f3a4a6a34d252f5251295a27d11418 (patch) | |
tree | fb9affe5aab371e64ceb6403818d6acd99203b97 | |
parent | 395a8a5f2a4976b80432a0d71d51d1bad3d01a83 (diff) |
Add the possiblity to reorder the column position for a board
-rw-r--r-- | assets/css/app.css | 2 | ||||
-rw-r--r-- | controllers/board.php | 104 | ||||
-rw-r--r-- | locales/fr_FR/translations.php | 4 | ||||
-rw-r--r-- | locales/pl_PL/translations.php | 6 | ||||
-rw-r--r-- | models/action.php | 6 | ||||
-rw-r--r-- | models/board.php | 182 | ||||
-rw-r--r-- | templates/board_edit.php | 39 | ||||
-rw-r--r-- | tests/BoardTest.php | 77 |
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&action=update&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&action=confirm&project_id=<?= $project['id'] ?>&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&action=moveUp&project_id=<?= $project['id'] ?>&column_id=<?= $column['id'] ?>"><?= t('Move Up') ?></a> + </li> + <?php endif ?> + <?php if ($column['position'] != count($columns)): ?> + <li> + <a href="?controller=board&action=moveDown&project_id=<?= $project['id'] ?>&column_id=<?= $column['id'] ?>"><?= t('Move Down') ?></a> + </li> + <?php endif ?> + <li> + <a href="?controller=board&action=confirm&project_id=<?= $project['id'] ?>&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']); + } +} |