Merge pull request #151 from nextcloud/sort-stacks

Add stack sorting functionality
This commit is contained in:
Julius Härtl
2017-05-23 23:07:04 +02:00
committed by GitHub
9 changed files with 141 additions and 9 deletions

View File

@@ -40,6 +40,7 @@ return [
['name' => 'stack#index', 'url' => '/stacks/{boardId}', 'verb' => 'GET'],
['name' => 'stack#create', 'url' => '/stacks', 'verb' => 'POST'],
['name' => 'stack#update', 'url' => '/stacks/{stackId}', 'verb' => 'PUT'],
['name' => 'stack#reorder', 'url' => '/stacks/{stackId}/reorder', 'verb' => 'PUT'],
['name' => 'stack#delete', 'url' => '/stacks/{stackId}', 'verb' => 'DELETE'],
['name' => 'stack#archived', 'url' => '/stacks/{boardId}/archived', 'verb' => 'GET'],

View File

@@ -398,6 +398,11 @@ button:hover {
margin: 10px;
border: 1px dashed #aaa;
}
#innerBoard > .as-sortable-placeholder {
display: inline-block !important;
margin-top: 0;
margin-left: 0;
}
.info {
padding-left: 5px;

View File

@@ -68,7 +68,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
$scope.stacksData = StackService;
$scope.stacks = {};
$scope.stacks = [];
$scope.$watch('stacksData', function (value) {
$scope.refreshData();
}, true);
@@ -87,7 +87,8 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
$scope.filterData = function (order, text) {
if ($scope.stacks === undefined)
return;
angular.copy(StackService.getAll(), $scope.stacks);
angular.copy(StackService.getData(), $scope.stacks);
$scope.stacks = $filter('orderBy')($scope.stacks, order);
angular.forEach($scope.stacks, function (value, key) {
var cards = $filter('cardSearchFilter')(value.cards, text);
cards = $filter('orderBy')(cards, order);
@@ -192,6 +193,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
// settings for card sorting
$scope.sortOptions = {
id: 'card',
itemMoved: function (event) {
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column;
var order = event.dest.index;
@@ -202,7 +204,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
CardService.update(card);
CardService.reorder(card, order).then(function (data) {
StackService.addCard(card);
StackService.reorder(card, order);
StackService.reorderCard(card, order);
StackService.removeCard({
id: card.id,
stackId: oldStack
@@ -214,13 +216,14 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
var card = event.source.itemScope.c;
var stack = event.dest.sortableScope.$parent.s.id;
CardService.reorder(card, order).then(function (data) {
StackService.reorder(card, order);
StackService.reorderCard(card, order);
$scope.refreshData();
});
},
scrollableContainer: '#board',
containerPositioning: 'relative',
containment: '#board',
longTouch: true,
// auto scroll on drag
dragMove: function (itemPosition, containment, eventObj) {
if (eventObj) {
@@ -239,6 +242,44 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
container.scrollTop(container.scrollTop() + 50);
}
}
},
accept: function (sourceItemHandleScope, destSortableScope, destItemScope) {
return sourceItemHandleScope.sortableScope.options.id === 'card';
}
};
$scope.sortOptionsStack = {
id: 'stack',
orderChanged: function (event) {
var order = event.dest.index;
var stack = event.source.itemScope.s;
StackService.reorder(stack, order).then(function (data) {
$scope.refreshData();
});
},
scrollableContainer: '#board',
containerPositioning: 'relative',
containment: '#board',
dragMove: function (itemPosition, containment, eventObj) {
if (eventObj) {
var container = $("#board");
var offset = container.offset();
var targetX = eventObj.pageX - (offset.left || container.scrollLeft());
var targetY = eventObj.pageY - (offset.top || container.scrollTop());
if (targetX < offset.left) {
container.scrollLeft(container.scrollLeft() - 50);
} else if (targetX > container.width()) {
container.scrollLeft(container.scrollLeft() + 50);
}
if (targetY < offset.top) {
container.scrollTop(container.scrollTop() - 50);
} else if (targetY > container.height()) {
container.scrollTop(container.scrollTop() + 50);
}
}
},
accept: function (sourceItemHandleScope, destSortableScope, destItemScope) {
return sourceItemHandleScope.sortableScope.options.id === 'stack';
}
};

View File

@@ -58,7 +58,22 @@ app.factory('StackService', function(ApiService, $http, $q){
this.data[entity.stackId].cards.push(entity);
};
StackService.prototype.reorder = function(entity, order) {
StackService.prototype.reorder = function(stack, order) {
var deferred = $q.defer();
var self = this;
$http.put(this.baseUrl + '/' + stack.id + '/reorder', {stackId: stack.id, order: order}).then(function (response) {
angular.forEach(response.data, function (value, key) {
var id = value.id;
self.data[id].order = value.order;
});
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while update ' + self.endpoint);
});
return deferred.promise;
};
StackService.prototype.reorderCard = function(entity, order) {
// assign new order
for(var i=0, j=0;i<this.data[entity.stackId].cards.length;i++) {
if(this.data[entity.stackId].cards[i].id === entity.id) {

View File

@@ -80,6 +80,16 @@ class StackController extends Controller {
return $this->stackService->update($id, $title, $boardId, $order);
}
/**
* @NoAdminRequired
* @param $stackId
* @param $order
* @return array
*/
public function reorder($stackId, $order) {
return $this->stackService->reorder($stackId, $order);
}
/**
* @NoAdminRequired
* @param $stackId

View File

@@ -102,4 +102,29 @@ class StackService {
$stack->setOrder($order);
return $this->stackMapper->update($stack);
}
public function reorder($id, $order) {
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_EDIT);
$stackToSort = $this->stackMapper->find($id);
$stacks = $this->stackMapper->findAll($stackToSort->getBoardId());
$result = [];
$i = 0;
foreach ($stacks as $stack) {
if ($stack->id === $id) {
$stack->setOrder($order);
}
if ($i === $order) {
$i++;
}
if ($stack->id !== $id) {
$stack->setOrder($i++);
}
$this->stackMapper->update($stack);
$result[$stack->getOrder()] = $stack;
}
return $result;
}
}

View File

@@ -42,11 +42,11 @@
<search on-search="search" class="ng-hide"></search>
<div id="innerBoard" data-ng-model="stacks">
<div class="stack" ng-repeat="s in stacks"
<div id="innerBoard" data-ng-model="stacks" data-as-sortable="sortOptionsStack">
<div class="stack" ng-repeat="s in stacks" data-as-sortable-item
data-columnindex="{{$index}}" id="column{{$index}}"
style="">
<h2><span ng-show="!s.status.editStack">{{ s.title }}</span>
<h2 data-as-sortable-item-handle><span ng-show="!s.status.editStack">{{ s.title }}</span>
<form ng-if="s.status.editStack" ng-submit="stackservice.update(s)">
<input type="text" placeholder="Add a new stack"
ng-blur="stackservice.update(s); s.status.editStack=false" ng-model="s.title"

View File

@@ -158,7 +158,34 @@ class StackServiceTest extends \PHPUnit_Framework_TestCase {
$stack->setOrder(1);
$result = $this->stackService->update(123, 'Foo', 2, 1);
$this->assertEquals($stack, $result);
}
public function testReorder() {
$this->permissionService->expects($this->once())->method('checkPermission');
$a = $this->createStack(1, 0);
$b = $this->createStack(2, 1);
$c = $this->createStack(3, 2);
$stacks = [$a, $b, $c];
$this->stackMapper->expects($this->once())
->method('find')
->with(1)
->willReturn($a);
$this->stackMapper->expects($this->once())
->method('findAll')
->willReturn($stacks);
$actual = $this->stackService->reorder(1, 2);
$a = $this->createStack(1, 2);
$b = $this->createStack(2, 0);
$c = $this->createStack(3, 1);
$expected = [$b, $c, $a];
$this->assertEquals($expected, $actual);
}
private function createStack($id, $order) {
$stack = new Stack();
$stack->setId($id);
$stack->setOrder($order);
return $stack;
}
}

View File

@@ -84,6 +84,14 @@ class StackControllerTest extends \PHPUnit_Framework_TestCase {
$this->assertEquals(1, $this->controller->update(1, 2, 3, 4));
}
public function testReorder() {
$this->stackService->expects($this->once())
->method('reorder')
->with(1, 2)
->willReturn(1);
$this->assertEquals(1, $this->controller->reorder(1, 2));
}
public function testDelete() {
$this->stackService->expects($this->once())
->method('delete')