Archive boards

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2017-05-04 10:58:35 +02:00
parent fa5cba631f
commit 8c04ea8dc9
23 changed files with 305 additions and 80 deletions

View File

@@ -65,6 +65,14 @@ button.button-inline:hover {
* Navigation sidebar
*/
.app-navigation-entry-menu ul {
flex-direction: row;
}
.app-navigation-entry-utils-menu-button {
display: block !important;
}
.app-navigation-entry-utils-menu-share {
display: flex !important;
padding: 14px;
@@ -318,8 +326,6 @@ button.button-inline:hover {
.popovermenu {
z-index: 999;
opacity: 1;
margin-top: 25px;
margin-right: 3px;
display: block;
}
@@ -614,23 +620,30 @@ button.button-inline:hover {
.colorselect {
overflow: hidden;
clear: both;
padding-top: 4px;
padding-left: 4px;
border-radius:3px;
flex-direction: row;
min-width: 240px;
height: 34px;
display: flex;
margin: 3px 3px 3px 0;
}
.colorselect .color {
opacity: 0.7;
width: 27px;
height: 27px;
float: left;
margin-right: 2px;
height: 100%;
flex-grow: 1;
border: none;
}
.colorselect .selected {
background-image: url(../../../core/img/actions/checkmark.svg);
background-position: center center;
background-repeat: no-repeat;
opacity: 1.0;
border: 1px solid #333333;
}
.colorselect .dark.selected {
background-image: url(../../../core/img/actions/checkmark-white.svg);
}
.labels .colorselect {
@@ -662,6 +675,16 @@ button.button-inline:hover {
cursor: pointer;
display: block;
}
#boardlist .app-popover-menu-utils {
width: 30px;
display: inline;
position: relative;
}
.popovermenu ul {
display: flex !important;
flex-direction: column;
}
#boardlist td {
padding: 10px;
@@ -680,16 +703,28 @@ button.button-inline:hover {
.cell-board-title {
width: 50%;
}
#boardlist .colorselect,
#boardlist input {
float: left;
#boardlist td form {
display: flex;
width: 100%;
}
#boardlist .colorselect {
margin-top: 5px;
#boardlist td .colorselect {
flex-grow: 1;
}
#boardlist td input[type=text] {
flex-grow: 2;
}
#boardlist td input[type=submit] {
width: 32px;
}
#boardlist .popovermenu {
top: 9px;
right: -36px;
}
/**
@@ -925,6 +960,10 @@ button.button-inline:hover {
* Custom icons
*/
.icon-deck {
background-image: url(../img/deck.svg);
}
.icon-group {
background-image: url('../../../settings/img/users.svg');
}

1
img/deck.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M432.3 448.1h-348c-13.2 0-24-10.8-24-24V264.6c0-13.2 10.8-24 24-24h348c13.2 0 24 10.8 24 24v159.5c0 13.2-10.8 24-24 24zM380.4 89.8H127.8c-7.7 0-14-6.3-14-14v-6.3c0-7.7 6.3-14 14-14h252.6c7.7 0 14 6.3 14 14v6.3c0 7.7-6.3 14-14 14zm19.4 61.8H110.6c-7.7 0-14-6.3-14-14v-6.3c0-7.7 6.3-14 14-14h289.2c7.7 0 14 6.3 14 14v6.3c0 7.7-6.3 14-14 14zm21.6 61.4H94.6c-7.7 0-14-6.3-14-14v-6.3c0-7.7 6.3-14 14-14h326.8c7.7 0 14 6.3 14 14v6.3c0 7.7-6.3 14-14 14z"/></svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -39,7 +39,10 @@ app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvid
.state('list', {
url: "/",
templateUrl: "/boardlist.mainView.html",
controller: 'ListController'
controller: 'ListController',
params: {
filter: { value: '' }
}
})
.state('board', {
url: "/board/:boardId/:filter",

View File

@@ -80,7 +80,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
}
};
$scope.checkCanEdit = function () {
return !$scope.archived;
return !BoardService.getCurrent().archived;
};
// filter cards here, as ng-sortable will not work nicely with html-inline filters

View File

@@ -48,9 +48,10 @@ app.controller('CardController', function ($scope, $rootScope, $routeParams, $lo
}
};
$scope.cardEditDescriptionShow = function($event) {
if(BoardService.isArchived() || CardService.getCurrent().archived) {
return false;
}
var node = $event.target.nodeName;
console.log($event);
console.log(BoardService);
if($scope.card.archived || !$scope.boardservice.canEdit()) {
console.log(node);
} else {

View File

@@ -21,11 +21,13 @@
*
*/
app.controller('ListController', function ($scope, $location, $filter, BoardService, $element, $timeout) {
app.controller('ListController', function ($scope, $location, $filter, BoardService, $element, $timeout, $stateParams) {
$scope.boards = [];
$scope.newBoard = {};
$scope.status = {
deleteUndo: []
deleteUndo: [],
filter: $stateParams.filter ? $stateParams.filter : '',
sidebar: false
};
$scope.colors = ['0082c9', '00c9c6','00c906', 'c92b00', 'F1DB50', '7C31CC', '3A3B3D', 'CACBCD'];
$scope.boardservice = BoardService;
@@ -42,9 +44,27 @@ app.controller('ListController', function ($scope, $location, $filter, BoardServ
$scope.filterData = function () {
angular.copy($scope.boardservice.getData(), $scope.boardservice.sorted);
$scope.boardservice.sidebar = $filter('orderBy')($scope.boardservice.sorted, 'title');
if ($scope.status.filter === 'archived') {
var filter = {};
filter[$scope.status.filter] = true;
$scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, filter);
} else if ($scope.status.filter === 'shared') {
$scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, {archived: false});
$scope.boardservice.sorted = $filter('boardFilterAcl')($scope.boardservice.sorted);
} else {
$scope.boardservice.sorted = $filter('cardFilter')($scope.boardservice.sorted, {archived: false});
}
$scope.boardservice.sorted = $filter('orderBy')($scope.boardservice.sorted, 'title');
};
$scope.$state = $stateParams;
$scope.$watch('$state.filter', function (name) {
$scope.status.filter = name;
$scope.filterData();
});
$scope.selectColor = function(color) {
$scope.newBoard.color = color;
};
@@ -72,11 +92,24 @@ app.controller('ListController', function ($scope, $location, $filter, BoardServ
board.status.edit = false;
};
$scope.boardArchive = function (board) {
board.archived = true;
BoardService.update(board).then(function(data) {
$scope.filterData();
});
};
$scope.boardUnarchive = function (board) {
board.archived = false;
BoardService.update(board).then(function(data) {
$scope.filterData();
});
};
$scope.boardDelete = function(board) {
var boardId = board.id;
$scope.status.deleteUndo[boardId] = 10;
$scope.boardDeleteCountdown = function () {
console.log($scope.status);
if($scope.status.deleteUndo[boardId] > 0) {
$scope.status.deleteUndo[boardId]--;
$timeout($scope.boardDeleteCountdown, 1000);

View File

@@ -0,0 +1,33 @@
/*
* @copyright Copyright (c) 2017 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
app.filter('boardFilterAcl', function() {
return function(boards) {
var _result = [];
angular.forEach(boards, function(board){
if(board.acl !== null && Object.keys(board.acl).length > 0) {
_result.push(board);
}
});
return _result;
};
});

View File

@@ -24,15 +24,16 @@
app.filter('cardFilter', function() {
return function(cards, rules) {
var _result = {};
var _result = [];
angular.forEach(cards, function(card){
var _card = card;
angular.some(rules, function(rule, condition) {
if(_card[rule]===condition) {
var keys = Object.keys(rules);
keys.some(function(key, condition) {
if(_card[key]===rules[key]) {
_result.push(_card);
}
});
});
return result;
return _result;
};
});

View File

@@ -24,7 +24,7 @@ app.filter('textColorFilter', function() {
return function (hex) {
// RGB2HLS by Garry Tan
// http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex);
var result = /^#?([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex);
var color = result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),

View File

@@ -190,6 +190,13 @@ app.factory('BoardService', function(ApiService, $http, $q){
return this.getCurrent().permissions['PERMISSION_SHARE'];
}
BoardService.prototype.isArchived = function () {
if(!this.getCurrent() || this.getCurrent().archived) {
return true;
}
return false;
};
service = new BoardService($http, 'boards', $q);
return service;

View File

@@ -23,12 +23,12 @@
namespace OCA\Deck;
class CardArchivedException extends \Exception {
class ArchivedItemException extends \Exception {
/**
* Constructor
* @param string $msg the error message
*/
public function __construct($msg = "") {
public function __construct($msg = "Operation not allowed. Item is archived.") {
parent::__construct($msg);
}
}

View File

@@ -96,8 +96,8 @@ class BoardController extends Controller {
* @param $color
* @return \OCP\AppFramework\Db\Entity
*/
public function update($id, $title, $color) {
return $this->boardService->update($id, $title, $color);
public function update($id, $title, $color, $archived) {
return $this->boardService->update($id, $title, $color, $archived);
}
/**

View File

@@ -23,9 +23,12 @@
namespace OCA\Deck\Service;
use OCA\Deck\ArchivedItemException;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\IPermissionMapper;
use OCA\Deck\Db\Label;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IL10N;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
@@ -80,6 +83,23 @@ class BoardService {
return $board;
}
public function isArchived($mapper, $id) {
try {
if ($mapper instanceof IPermissionMapper) {
$boardId = $mapper->findBoardId($id);
} else {
$boardId = $id;
}
if ($boardId === null) {
return false;
}
} catch (DoesNotExistException $exception) {
return false;
}
$board = $this->find($boardId);
return $board->getArchived();
}
public function create($title, $userId, $color) {
@@ -115,11 +135,12 @@ class BoardService {
return $this->boardMapper->delete($this->find($id));
}
public function update($id, $title, $color) {
public function update($id, $title, $color, $archived) {
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
$board = $this->find($id);
$board->setTitle($title);
$board->setColor($color);
$board->setArchived($archived);
$this->boardMapper->mapOwner($board);
return $this->boardMapper->update($board);
}

View File

@@ -26,18 +26,22 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\Acl;
use OCA\Deck\CardArchivedException;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\StatusException;
class CardService {
private $cardMapper;
private $stackMapper;
private $permissionService;
private $boardService;
public function __construct(CardMapper $cardMapper, StackMapper $stackMapper, PermissionService $permissionService) {
public function __construct(CardMapper $cardMapper, StackMapper $stackMapper, PermissionService $permissionService, BoardService $boardService) {
$this->cardMapper = $cardMapper;
$this->stackMapper = $stackMapper;
$this->permissionService = $permissionService;
$this->boardService = $boardService;
}
public function find($cardId) {
@@ -51,6 +55,9 @@ class CardService {
*/
public function create($title, $stackId, $type, $order, $owner) {
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->stackMapper, $stackId)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = new Card();
$card->setTitle($title);
$card->setStackId($stackId);
@@ -63,14 +70,20 @@ class CardService {
public function delete($id) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
return $this->cardMapper->delete($this->cardMapper->find($id));
}
public function update($id, $title, $stackId, $type, $order, $description, $owner) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
if ($card->getArchived()) {
throw new CardArchivedException();
throw new StatusException('Operation not allowed. This card is archived.');
}
$card->setTitle($title);
$card->setStackId($stackId);
@@ -83,9 +96,12 @@ class CardService {
public function rename($id, $title) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
if ($card->getArchived()) {
throw new CardArchivedException();
throw new StatusException('Operation not allowed. This card is archived.');
}
$card->setTitle($title);
return $this->cardMapper->update($card);
@@ -93,12 +109,15 @@ class CardService {
public function reorder($id, $stackId, $order) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$cards = $this->cardMapper->findAll($stackId);
$result = [];
$i = 0;
foreach ($cards as $card) {
if ($card->getArchived()) {
throw new CardArchivedException();
throw new StatusException('Operation not allowed. This card is archived.');
}
if ($card->id === $id) {
$card->setOrder($order);
@@ -121,6 +140,9 @@ class CardService {
public function archive($id) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
$card->setArchived(true);
return $this->cardMapper->update($card);
@@ -128,6 +150,9 @@ class CardService {
public function unarchive($id) {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
$card->setArchived(false);
return $this->cardMapper->update($card);
@@ -135,18 +160,24 @@ class CardService {
public function assignLabel($cardId, $labelId) {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $cardId)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($cardId);
if ($card->getArchived()) {
throw new CardArchivedException();
throw new StatusException('Operation not allowed. This card is archived.');
}
$this->cardMapper->assignLabel($cardId, $labelId);
}
public function removeLabel($cardId, $labelId) {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
if($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($cardId);
if ($card->getArchived()) {
throw new CardArchivedException();
throw new StatusException('Operation not allowed. This card is archived.');
}
$this->cardMapper->removeLabel($cardId, $labelId);
}

View File

@@ -26,15 +26,22 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\StatusException;
class LabelService {
/** @var LabelMapper */
private $labelMapper;
/** @var PermissionService */
private $permissionService;
/** @var BoardService */
private $boardService;
public function __construct(LabelMapper $labelMapper, PermissionService $permissionService) {
public function __construct(LabelMapper $labelMapper, PermissionService $permissionService, BoardService $boardService) {
$this->labelMapper = $labelMapper;
$this->permissionService = $permissionService;
$this->boardService = $boardService;
}
public function find($labelId) {
@@ -44,6 +51,9 @@ class LabelService {
public function create($title, $color, $boardId) {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
if($this->boardService->isArchived(null, $boardId)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$label = new Label();
$label->setTitle($title);
$label->setColor($color);
@@ -53,11 +63,17 @@ class LabelService {
public function delete($id) {
$this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE);
if($this->boardService->isArchived($this->labelMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
return $this->labelMapper->delete($this->find($id));
}
public function update($id, $title, $color) {
$this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE);
if($this->boardService->isArchived($this->labelMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$label = $this->find($id);
$label->setTitle($title);
$label->setColor($color);

View File

@@ -31,6 +31,7 @@ use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\StatusException;
class StackService {
@@ -39,12 +40,14 @@ class StackService {
private $cardMapper;
private $labelMapper;
private $permissionService;
private $boardService;
public function __construct(StackMapper $stackMapper, CardMapper $cardMapper, LabelMapper $labelMapper, PermissionService $permissionService) {
public function __construct(StackMapper $stackMapper, CardMapper $cardMapper, LabelMapper $labelMapper, PermissionService $permissionService, BoardService $boardService) {
$this->stackMapper = $stackMapper;
$this->cardMapper = $cardMapper;
$this->labelMapper = $labelMapper;
$this->permissionService = $permissionService;
$this->boardService = $boardService;
}
public function findAll($boardId) {
@@ -81,6 +84,9 @@ class StackService {
public function create($title, $boardId, $order) {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
if($this->boardService->isArchived(null, $boardId)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$stack = new Stack();
$stack->setTitle($title);
$stack->setBoardId($boardId);
@@ -96,6 +102,9 @@ class StackService {
public function update($id, $title, $boardId, $order) {
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE);
if($this->boardService->isArchived($this->stackMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$stack = $this->stackMapper->find($id);
$stack->setTitle($title);
$stack->setBoardId($boardId);

View File

@@ -45,7 +45,7 @@ if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
'app' => ['App', 'Config', 'Run'],
'controller' => ['AppController', 'BoardController', 'CardController', 'ListController'],
'directive' => ['appnavigationentryutils', 'appPopoverMenuUtils', 'autofocusoninsert', 'avatar', 'elastic', 'search'],
'filters' => ['cardFilter', 'cardSearchFilter', 'iconWhiteFilter', 'lightenColorFilter', 'orderObjectBy', 'relativeDateFilter', 'textColorFilter'],
'filters' => ['boardFilterAcl', 'cardFilter', 'cardSearchFilter', 'iconWhiteFilter', 'lightenColorFilter', 'orderObjectBy', 'relativeDateFilter', 'textColorFilter'],
'service' => ['ApiService', 'BoardService', 'CardService', 'LabelService', 'StackService', 'StatusService'],
];
foreach($js as $folder=>$files) {
@@ -58,7 +58,7 @@ if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
<div id="app" class="app-deck" data-ng-app="Deck" ng-controller="AppController" ng-cloak>
<div id="app-navigation" data-ng-controller="ListController">
<div id="app-navigation" data-ng-controller="ListController" ng-init="initSidebar()">
<?php print_unescaped($this->inc('part.navigation')); ?>
<?php /* print_unescaped($this->inc('part.settings')); */ ?>
</div>

View File

@@ -70,40 +70,37 @@
</div>
<div class="card-controls">
<i class="icon icon-filetype-text" ng-if="c.description" title="{{ c.description }}"></i>
<div class="app-popover-menu-utils">
<div class="app-popover-menu-utils" ng-if="!boardservice.isArchived>
<button class="button-inline card-options icon-more" ng-model="card"></button>
<div class="popovermenu hidden">
<ul>
<li ng-if="filter!=='archive'">
<a class="menuitem action action-rename permanent"
data-action="Archive"
ng-click="cardArchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Archive')); ?></span></a>
data-action="Archive"
ng-click="cardArchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Archive')); ?></span></a>
</li>
<li ng-if="filter==='archive'">
<a class="menuitem action action-rename permanent"
data-action="Unarchive"
ng-click="cardUnarchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Unarchive')); ?></span></a>
data-action="Unarchive"
ng-click="cardUnarchive(c); $event.stopPropagation();"><span
class="icon icon-archive"></span><span><?php p($l->t('Unarchive')); ?></span></a>
</li>
<li>
<a class="menuitem action action-delete permanent"
data-action="Delete"
ng-click="cardDelete(c)"><span
class="icon icon-delete"></span><span><?php p($l->t('Delete')); ?></span></a>
data-action="Delete"
ng-click="cardDelete(c)"><span
class="icon icon-delete"></span><span><?php p($l->t('Delete')); ?></span></a>
</li>
</ul>
</div>
</div>
</div>
<!--<span class="info due"><i class="fa fa-clock-o" aria-hidden="true"></i> <span>Today</span></span>
<span class="info tasks"><i class="fa fa-list" aria-hidden="true"></i> <span>3/12</span></span>
//-->
</div>
</li>
</ul>
<!-- CREATE CARD //-->
<div class="card create"
style="background-color:#{{ boardservice.getCurrent().color }};" ng-if="boardservice.canEdit() && checkCanEdit() && filter!=='archive'">

View File

@@ -5,31 +5,61 @@
<td class="cell-board-bullet"></td>
<td class="cell-board-title" width="90%"><?php p($l->t('Title')); ?></td>
<td class="cell-board-members"><?php p($l->t('Members')); ?></td>
<td></td>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="b in boardservice.sorted"
ui-sref="board({boardId: b.id})">
<td>
<tr data-ng-repeat="b in boardservice.sorted">
<td ui-sref="board({boardId: b.id})">
<span class="board-bullet"
style="background-color:#{{b.color}};"> </span>
</td>
<td><a href="#/board/{{b.id}}">{{ b.title }}</a></td>
<td ui-sref="board({boardId: b.id})"><a href="#/board/{{b.id}}">{{ b.title }}</a></td>
<td>
<div id="assigned-users">
<div class="avatardiv" avatar displayname="{{ b.owner.uid }}" title="{{ b.owner.displayname }}"></div>
<div class="avatardiv" avatar displayname="{{ acl.participant.uid }}" title="{{ acl.participant.uid }}" ng-repeat="acl in b.acl | limitTo: 7"></div>
</div>
</td>
</tr>
<tr>
<td><span class="icon icon-add"></span></td>
<td>
<div class="app-popover-menu-utils">
<button class="icon icon-more"></button>
<div class="popovermenu bubble hidden">
<ul>
<li ng-if="boardservice.canManage() && !b.archived" ng-click="boardArchive(b)">
<a class="menuitem"><span class="icon-archive"></span> <?php p($l->t('Archive board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage() && b.archived" ng-click="boardUnarchive(b)">
<a class="menuitem"><span class="icon-archive"></span> <?php p($l->t('Unarchive board')); ?>
</a>
</li>
<li ng-if="boardservice.canManage() && b.archived" ng-click="boardDelete(b)">
<a class="menuitem"><span class="icon-delete"></span> <?php p($l->t('Delete board')); ?>
</a>
</li>
<li ui-sref="board.detail({boardId: b.id})">
<a class="menuitem"><span class="icon-settings-dark"></span> <?php p($l->t('Board settings')); ?>
</a>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr ng-if="status.filter === '' && !status.addBoard" ng-click="status.addBoard=!status.addBoard">
<td><span class="icon icon-add"></span></td>
<td colspan="3">
<a ng-click="status.addBoard=!status.addBoard"
ng-show="!status.addBoard">
<?php p($l->t('Create new board')); ?>
</a>
<form ng-show="status.addBoard" ng-disabled="isAddingList"
</td>
</tr>
<tr ng-if="status.filter === '' && status.addBoard">
<td><span class="icon icon-add"></span></td>
<td>
<form ng-disabled="isAddingList"
class="ng-pristine ng-valid" ng-submit="boardCreate()">
<input id="newTitle" class="edit ng-valid ng-empty"
type="text" placeholder="<?php p($l->t('New board title')); ?>"
@@ -38,13 +68,13 @@
<div class="color" ng-repeat="c in colors"
style="background-color:#{{ c }};"
ng-click="selectColor(c)"
ng-class="{'selected': (c == newBoard.color) }">
<br/></div>
ng-class="{'selected': (c == newBoard.color), 'dark': (newBoard.color | textColorFilter) === '#ffffff' }"></div>
</div>
<input type="submit" value="" class="icon-checkmark svg">
<input type="submit" value="" class="icon-checkmark svg" />
</form>
</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

View File

@@ -31,6 +31,7 @@
<div id="labels">
<ui-select multiple tagging="" ng-model="card.labels" theme="select2"
ng-disabled="boardservice.isArchived() || card.archived"
style="width:100%;" title="Choose a label"
placeholder="Add a label"
on-select="labelAssign($item, $model)"

View File

@@ -1,8 +1,10 @@
<ul class="with-icon">
<li><a href="#" class=""><?php p($l->t('All Boards')); ?></a></li>
<li><a ui-sref="list({ filter: ''})" class="icon-deck"><?php p($l->t('All Boards')); ?></a></li>
<li><a ui-sref="list({ filter: 'archived' })" class="icon-archive"><?php p($l->t('Archived boards')); ?></a></li>
<li><a ui-sref="list({ filter: 'shared' })" class="icon-share"><?php p($l->t('Shared boards')); ?></a></li>
<li class="with-icon with-menu" ng-class="{active: b.id === boardservice.getCurrent().id}" data-ng-repeat="b in boardservice.sorted">
<li class="with-icon with-menu" ng-class="{active: b.id === boardservice.getCurrent().id}" data-ng-repeat="b in boardservice.sidebar">
<span class="board-bullet" style="background-color:#{{b.color}};" ng-if="!b.status.edit"> </span>
<a href="#!/board/{{b.id}}/" ng-if="!b.status.edit">{{ b.title }}</a>
<div class="app-navigation-entry-utils" ng-show="!b.status.edit" style="position:absolute;">
@@ -16,7 +18,7 @@
<ul>
<li ng-show="b.owner.uid===user"><button class="icon-rename svg" title="<?php p($l->t('edit')); ?>" ng-click="b.status.edit=true"></button></li>
<li ng-show="b.owner.uid===user"><button class="icon-delete svg" title="<?php p($l->t('delete')); ?>" ng-click="boardDelete(b)"></button></li>
<li ng-show="b.owner.uid!==user && false"><button class="icon-delete svg" title="<?php p($l->t('remove share')); ?>" ng-click="boardRemoveShare(b)"></button></li>
<li ng-show="b.owner.uid===user"><button class="icon-archive svg" title="<?php p($l->t('Move board to archive')); ?>" ng-click="boardArchive(b)"></button></li>
</ul>
</div>
<div class="app-navigation-entry-deleted" ng-show="false">

View File

@@ -23,7 +23,7 @@
namespace OCA\Deck\Db;
use OCA\Deck\CardArchivedException;
use OCA\Deck\ArchivedItemException;
use OCA\Deck\Controller\PageController;
use OCA\Deck\NoPermissionException;
use OCA\Deck\NotFoundException;
@@ -45,7 +45,7 @@ class ExceptionsTest extends \PHPUnit_Framework_TestCase {
}
public function testCardArchivedException() {
$e = new CardArchivedException('foo');
$e = new ArchivedItemException('foo');
$this->assertEquals('foo', $e->getMessage());
}

View File

@@ -27,7 +27,7 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\CardArchivedException;
use OCA\Deck\ArchivedItemException;
class CardServiceTest extends \PHPUnit_Framework_TestCase {
@@ -108,7 +108,7 @@ class CardServiceTest extends \PHPUnit_Framework_TestCase {
$card->setArchived(true);
$this->cardMapper->expects($this->once())->method('find')->willReturn($card);
$this->cardMapper->expects($this->never())->method('update');
$this->setExpectedException(CardArchivedException::class);
$this->setExpectedException(ArchivedItemException::class);
$this->cardService->update(123, 'newtitle', 234, 'text', 999, 'foo', 'admin');
}
@@ -128,7 +128,7 @@ class CardServiceTest extends \PHPUnit_Framework_TestCase {
$card->setArchived(true);
$this->cardMapper->expects($this->once())->method('find')->willReturn($card);
$this->cardMapper->expects($this->never())->method('update');
$this->setExpectedException(CardArchivedException::class);
$this->setExpectedException(ArchivedItemException::class);
$this->cardService->rename(123, 'newtitle');
}
@@ -168,7 +168,7 @@ class CardServiceTest extends \PHPUnit_Framework_TestCase {
$card->setArchived(true);
$this->cardMapper->expects($this->once())->method('findAll')->willReturn([$card]);
$this->cardMapper->expects($this->never())->method('update')->willReturnCallback(function($c) { return $c; });
$this->setExpectedException(CardArchivedException::class);
$this->setExpectedException(ArchivedItemException::class);
$actual = $this->cardService->reorder(123, 234, 1);
}
public function testArchive() {
@@ -204,7 +204,7 @@ class CardServiceTest extends \PHPUnit_Framework_TestCase {
$card->setArchived(true);
$this->cardMapper->expects($this->once())->method('find')->willReturn($card);
$this->cardMapper->expects($this->never())->method('assignLabel');
$this->setExpectedException(CardArchivedException::class);
$this->setExpectedException(ArchivedItemException::class);
$this->cardService->assignLabel(123, 999);
}
@@ -221,7 +221,7 @@ class CardServiceTest extends \PHPUnit_Framework_TestCase {
$card->setArchived(true);
$this->cardMapper->expects($this->once())->method('find')->willReturn($card);
$this->cardMapper->expects($this->never())->method('removeLabel');
$this->setExpectedException(CardArchivedException::class);
$this->setExpectedException(ArchivedItemException::class);
$this->cardService->removeLabel(123, 999);
}