Merge pull request #556 from nextcloud/release/v0.4.1

Prepare 0.4.1
This commit is contained in:
Julius Härtl
2018-07-28 13:40:08 +02:00
committed by GitHub
15 changed files with 136 additions and 68 deletions

View File

@@ -1,6 +1,18 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## 0.4.1 - 2018-07-28
### Added
- Make app compatible with Nextcloud 14
### Fixed
- Fix bug with file upload on unlimited quota
- Fix issue on MySQL databases that don't support 4-byte characters
- Fix check when assigning users
## 0.4.0 - 2018-07-11 ## 0.4.0 - 2018-07-11
### Added ### Added

View File

@@ -14,7 +14,7 @@
- 🚀 Get your project organized - 🚀 Get your project organized
</description> </description>
<version>0.4.1-dev1</version> <version>0.4.1</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>Julius Härtl</author> <author>Julius Härtl</author>
<namespace>Deck</namespace> <namespace>Deck</namespace>

38
css/comp-13.scss Normal file
View File

@@ -0,0 +1,38 @@
#content-wrapper #content {
height: 100%;
}
#app-content {
flex-grow: 1;
height: 100%;
&.details-visible {
margin-right: 500px;
}
}
#app-sidebar {
right: -500px;
max-width: 100%;
width: 500px;
display:flex;
flex-direction: column;
&.details-visible {
right: 0;
}
}
#content[class*='app-'] * {
box-sizing: border-box;
}
body:not(.snapjs-left) {
.app-navigation-hide {
#app-content {
margin-left: 0 !important;
}
#app-navigation {
display: none;
}
}
}

View File

@@ -70,6 +70,26 @@ input.input-inline {
cursor: text; cursor: text;
} }
/**
* Generic app layout
*/
#content {
height: 100%;
min-height: initial;
}
.app.app-deck {
width: 100%;
height: 100%;
display: flex;
}
#app-content {
display: flex;
flex-direction: column;
}
/** /**
* Navigation sidebar * Navigation sidebar
*/ */
@@ -238,7 +258,7 @@ input.input-inline {
} }
} }
#app-navigation-toggle { #app-navigation-toggle-custom {
width: 44px; width: 44px;
height: 44px; height: 44px;
cursor: pointer; cursor: pointer;
@@ -617,17 +637,6 @@ input.input-inline {
/** /**
* App sidebar * App sidebar
*/ */
#app-sidebar {
right: -500px;
max-width: 100%;
width: 500px;
display:flex;
flex-direction: column;
&.details-visible {
right: 0;
}
}
#sidebar-header { #sidebar-header {
h3 { h3 {
@@ -922,16 +931,6 @@ input.input-inline {
} }
} }
#app-content {
overflow: hidden;
display: flex;
flex-direction: column;
&.details-visible {
margin-right: 500px;
}
}
.labels { .labels {
display: block; display: block;
overflow: hidden; overflow: hidden;
@@ -1434,3 +1433,22 @@ input.input-inline {
.ui-select-dropdown.select2-drop-active { .ui-select-dropdown.select2-drop-active {
opacity: 1 !important; opacity: 1 !important;
} }
/**
* Custom app sidebar handling
*/
body:not(.snapjs-left) {
.app-navigation-hide {
#app-content {
margin-left: 0 !important; /* overwrite margin since we want the translateX to handle it*/
}
#app-navigation {
transform: translateX(-300px);
}
}
}
@media only screen and (max-width: 768px) {
#app-navigation-toggle-custom {
display: none;
}
}

View File

@@ -71,8 +71,9 @@ app.config(function ($provide, $interpolateProvider, $httpProvider, $urlRouterPr
tab: {value: 0, dynamic: true}, tab: {value: 0, dynamic: true},
}, },
views: { views: {
'sidebarView': { 'sidebarView@': {
templateUrl: '/board.sidebarView.html' templateUrl: '/board.sidebarView.html',
controller: 'BoardController'
} }
} }
}) })
@@ -82,7 +83,7 @@ app.config(function ($provide, $interpolateProvider, $httpProvider, $urlRouterPr
tab: {value: 0, dynamic: true}, tab: {value: 0, dynamic: true},
}, },
views: { views: {
'sidebarView': { 'sidebarView@': {
templateUrl: '/card.sidebarView.html', templateUrl: '/card.sidebarView.html',
controller: 'CardController' controller: 'CardController'
} }

View File

@@ -56,26 +56,6 @@ app.run(function ($document, $rootScope, $transitions, BoardService) {
OC.filePath('deck', 'img', 'app-512.png') OC.filePath('deck', 'img', 'app-512.png')
); );
$('#app-navigation-toggle').off('click');
// App sidebar on mobile
var snapper = new Snap({
element: document.getElementById('app-content'),
disable: 'right',
maxPosition: 250,
touchToDrag: false
});
$('#app-navigation-toggle').click(function () {
if ($(window).width() > 768) {
$('#app-navigation').toggle('hidden');
} else {
if (snapper.state().state === 'left') {
snapper.close();
} else {
snapper.open('left');
}
}
});
// Select all elements with data-toggle="tooltips" in the document // Select all elements with data-toggle="tooltips" in the document
$('body').tooltip({ $('body').tooltip({
selector: '[data-toggle="tooltip"]' selector: '[data-toggle="tooltip"]'

View File

@@ -30,4 +30,13 @@ app.controller('AppController', function ($scope, $location, $http, $log, $rootS
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.user = oc_current_user; $scope.user = oc_current_user;
$rootScope.config = JSON.parse($attrs.config); $rootScope.config = JSON.parse($attrs.config);
$scope.appNavigationHide = false;
$scope.toggleSidebar = function() {
if ($(window).width() > 768) {
$scope.appNavigationHide = !$scope.appNavigationHide;
console.log($scope.appNavigationHide);
}
};
}); });

View File

@@ -61,6 +61,10 @@ class Application extends App {
return $container->getServer()->getConfig()->getSystemValue('dbtype', 'sqlite'); return $container->getServer()->getConfig()->getSystemValue('dbtype', 'sqlite');
}); });
$container->registerService('database4ByteSupport', function($container) {
return $container->getServer()->getDatabaseConnection()->supports4ByteText();
});
// Delete user/group acl entries when they get deleted // Delete user/group acl entries when they get deleted
/** @var IUserManager $userManager */ /** @var IUserManager $userManager */
$userManager = $server->getUserManager(); $userManager = $server->getUserManager();

View File

@@ -46,7 +46,7 @@ class PageController extends Controller {
public function index() { public function index() {
$params = [ $params = [
'user' => $this->userId, 'user' => $this->userId,
'maxUploadSize' => \OCP\Util::uploadLimit(), 'maxUploadSize' => (int)\OCP\Util::uploadLimit(),
]; ];
return new TemplateResponse('deck', 'main', $params); return new TemplateResponse('deck', 'main', $params);
} }

View File

@@ -38,29 +38,40 @@ class CardMapper extends DeckMapper implements IPermissionMapper {
/** @var IManager */ /** @var IManager */
private $notificationManager; private $notificationManager;
private $databaseType; private $databaseType;
private $database4ByteSupport;
public function __construct( public function __construct(
IDBConnection $db, IDBConnection $db,
LabelMapper $labelMapper, LabelMapper $labelMapper,
IUserManager $userManager, IUserManager $userManager,
IManager $notificationManager, IManager $notificationManager,
$databaseType = 'sqlite' $databaseType = 'sqlite',
$database4ByteSupport = true
) { ) {
parent::__construct($db, 'deck_cards', Card::class); parent::__construct($db, 'deck_cards', Card::class);
$this->labelMapper = $labelMapper; $this->labelMapper = $labelMapper;
$this->userManager = $userManager; $this->userManager = $userManager;
$this->notificationManager = $notificationManager; $this->notificationManager = $notificationManager;
$this->databaseType = $databaseType; $this->databaseType = $databaseType;
$this->database4ByteSupport = $database4ByteSupport;
} }
public function insert(Entity $entity) { public function insert(Entity $entity) {
$entity->setDatabaseType($this->databaseType); $entity->setDatabaseType($this->databaseType);
$entity->setCreatedAt(time()); $entity->setCreatedAt(time());
$entity->setLastModified(time()); $entity->setLastModified(time());
if (!$this->database4ByteSupport) {
$description = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $entity->getDescription());
$entity->setDescription($description);
}
return parent::insert($entity); return parent::insert($entity);
} }
public function update(Entity $entity, $updateModified = true) { public function update(Entity $entity, $updateModified = true) {
if (!$this->database4ByteSupport) {
$description = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $entity->getDescription());
$entity->setDescription($description);
}
$entity->setDatabaseType($this->databaseType); $entity->setDatabaseType($this->databaseType);
if ($updateModified) { if ($updateModified) {

View File

@@ -195,6 +195,7 @@ class CardService {
} }
public function assignUser($cardId, $userId) { public function assignUser($cardId, $userId) {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
$assignments = $this->assignedUsersMapper->find($cardId); $assignments = $this->assignedUsersMapper->find($cardId);
foreach ($assignments as $assignment) { foreach ($assignments as $assignment) {
if ($assignment->getParticipant() === $userId) { if ($assignment->getParticipant() === $userId) {
@@ -208,6 +209,7 @@ class CardService {
} }
public function unassignUser($cardId, $userId) { public function unassignUser($cardId, $userId) {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
$assignments = $this->assignedUsersMapper->find($cardId); $assignments = $this->assignedUsersMapper->find($cardId);
foreach ($assignments as $assignment) { foreach ($assignments as $assignment) {
if ($assignment->getParticipant() === $userId) { if ($assignment->getParticipant() === $userId) {

View File

@@ -28,32 +28,30 @@ Util::addScript('deck', 'build/vendor');
Util::addStyle('deck', 'style'); Util::addStyle('deck', 'style');
Util::addScript('deck', 'build/deck'); Util::addScript('deck', 'build/deck');
if (\OC_Util::getVersion()[0] < 14) {
Util::addStyle('deck', 'comp-13');
}
?> ?>
<div id="app" class="app-deck" data-ng-app="Deck" ng-controller="AppController" ng-cloak config="<?php p(json_encode($_)); ?>"> <div class="app app-deck" data-ng-app="Deck" ng-controller="AppController" ng-cloak config="<?php p(json_encode($_)); ?>" ng-class="{'app-navigation-hide': appNavigationHide}">
<div id="app-navigation" data-ng-controller="ListController" ng-init="initSidebar()"> <div id="app-navigation" data-ng-controller="ListController" ng-init="initSidebar()">
<?php print_unescaped($this->inc('part.navigation')); ?> <?php print_unescaped($this->inc('part.navigation')); ?>
<?php /* print_unescaped($this->inc('part.settings')); */ ?> <?php /* print_unescaped($this->inc('part.settings')); */ ?>
</div> </div>
<div id="app-content" ng-class="{ 'details-visible': sidebar.show }"> <div id="app-content" ng-class="{ 'details-visible': sidebar.show }"><div id="app-navigation-toggle-custom" class="icon-menu" ng-click="toggleSidebar()"></div><div ui-view></div></div>
<div ui-view></div> <div id="app-sidebar" ng-class="{ 'details-visible': sidebar.show }" ng-if="sidebar.show" class="details-view scroll-container" ui-view="sidebarView"></div>
</div>
<route-loading-indicator></route-loading-indicator> <route-loading-indicator></route-loading-indicator>
<script type="text/ng-template" id="/boardlist.mainView.html"> <script type="text/ng-template" id="/boardlist.mainView.html">
<?php print_unescaped($this->inc('part.boardlist')); ?> <?php print_unescaped($this->inc('part.boardlist')); ?>
</script> </script>
<script type="text/ng-template" id="/board.sidebarView.html"> <script type="text/ng-template" id="/board.sidebarView.html">
<?php print_unescaped($this->inc('part.board.sidebarView')); ?> <?php print_unescaped($this->inc('part.board.sidebarView')); ?>
</script> </script>
<script type="text/ng-template" id="/board.mainView.html">
<?php print_unescaped($this->inc('part.board.mainView')); ?>
</script>
<script type="text/ng-template" id="/board.html"> <script type="text/ng-template" id="/board.html">
<?php print_unescaped($this->inc('part.board')); ?> <?php print_unescaped($this->inc('part.board.mainView')); ?>
</script> </script>
<script type="text/ng-template" id="/card.sidebarView.html"> <script type="text/ng-template" id="/card.sidebarView.html">
<?php print_unescaped($this->inc('part.card')); ?> <?php print_unescaped($this->inc('part.card')); ?>
@@ -62,4 +60,4 @@ Util::addScript('deck', 'build/deck');
<?php print_unescaped($this->inc('part.card.attachments')); ?> <?php print_unescaped($this->inc('part.card.attachments')); ?>
</script> </script>
</div> </div>

View File

@@ -37,7 +37,6 @@
</div> </div>
<div id="board" class="scroll-container" ng-click="sidebar.show=false" ui-sref="board" ng-class="{'card-selected': params.cardId}"> <div id="board" class="scroll-container" ng-click="sidebar.show=false" ui-sref="board" ng-class="{'card-selected': params.cardId}">
{{ cardOpen }}
<search on-search="search" class="ng-hide"></search> <search on-search="search" class="ng-hide"></search>
<div id="innerBoard" data-ng-model="stacks" data-as-sortable="sortOptionsStack"> <div id="innerBoard" data-ng-model="stacks" data-as-sortable="sortOptionsStack">

View File

@@ -1,4 +0,0 @@
<?php print_unescaped($this->inc('part.board.mainView')); ?>
<div id="app-sidebar" class="details-view scroll-container"
ng-class="{ 'details-visible': sidebar.show }" ui-view="sidebarView">
</div>

View File

@@ -1,5 +1,5 @@
<div nv-file-drop="" uploader="uploader" class="drop-zone" options="{cardId: cardservice.getCurrent().id}"> <div nv-file-drop="" uploader="fileservice.uploader" class="drop-zone" options="{cardId: cardservice.getCurrent().id}">
<div class="drop-indicator" nv-file-over uploader="uploader"> <div class="drop-indicator" nv-file-over uploader="fileservice.uploader">
<p><?php p($l->t('Drop your files here to upload it to the card')); ?></p> <p><?php p($l->t('Drop your files here to upload it to the card')); ?></p>
</div> </div>
<div id="board-status" ng-if="statusservice.active"> <div id="board-status" ng-if="statusservice.active">
@@ -97,8 +97,8 @@
<span class="save-indicator saved"><?php p($l->t('Saved')); ?></span> <span class="save-indicator saved"><?php p($l->t('Saved')); ?></span>
<span class="save-indicator unsaved"><?php p($l->t('Unsaved changes')); ?></span> <span class="save-indicator unsaved"><?php p($l->t('Unsaved changes')); ?></span>
<a ng-if="params.tab === 0" href="https://github.com/nextcloud/deck/wiki/Markdown-Help" target="_blank" class="icon icon-help" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Formatting help')); ?>"><span class="hidden-visually"><?php p($l->t('Formatting help')); ?></span></a> <a ng-if="params.tab === 0" href="https://github.com/nextcloud/deck/wiki/Markdown-Help" target="_blank" class="icon icon-help" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Formatting help')); ?>"><span class="hidden-visually"><?php p($l->t('Formatting help')); ?></span></a>
<label ng-if="params.tab === 1" for="attachment-upload" class="button icon-upload" ng-class="{'icon-loading-small': uploader.isUploading}" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Upload attachment')); ?>"></label> <label ng-if="params.tab === 1" for="attachment-upload" class="button icon-upload" ng-class="{'icon-loading-small': fileservice.uploader.isUploading}" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Upload attachment')); ?>"></label>
<input id="attachment-upload" type="file" nv-file-select="" uploader="uploader" class="hidden" options="{cardId: cardservice.getCurrent().id}"/> <input id="attachment-upload" type="file" nv-file-select="" uploader="fileservice.uploader" class="hidden" options="{cardId: cardservice.getCurrent().id}"/>
<input ng-if="status.cardEditDescription" type="button" ng-mousedown="status.continueEdit = true; status.selectAttachment = true;" class="icon-files-dark" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Insert attachment')); ?>"/> <input ng-if="status.cardEditDescription" type="button" ng-mousedown="status.continueEdit = true; status.selectAttachment = true;" class="icon-files-dark" data-toggle="tooltip" data-placement="left" title="<?php p($l->t('Insert attachment')); ?>"/>
</div> </div>