Implement due dates for cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
committed by
Julius Härtl
parent
58bf51accd
commit
9a77bd7c7c
@@ -130,7 +130,6 @@
|
|||||||
<name>last_modified</name>
|
<name>last_modified</name>
|
||||||
<type>integer</type>
|
<type>integer</type>
|
||||||
<default></default>
|
<default></default>
|
||||||
<length>8</length>
|
|
||||||
<notnull>false</notnull>
|
<notnull>false</notnull>
|
||||||
<unsigned>true</unsigned>
|
<unsigned>true</unsigned>
|
||||||
</field>
|
</field>
|
||||||
@@ -138,7 +137,6 @@
|
|||||||
<name>created_at</name>
|
<name>created_at</name>
|
||||||
<type>integer</type>
|
<type>integer</type>
|
||||||
<default></default>
|
<default></default>
|
||||||
<length>8</length>
|
|
||||||
<notnull>false</notnull>
|
<notnull>false</notnull>
|
||||||
<unsigned>true</unsigned>
|
<unsigned>true</unsigned>
|
||||||
</field>
|
</field>
|
||||||
@@ -159,6 +157,11 @@
|
|||||||
<type>boolean</type>
|
<type>boolean</type>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</field>
|
</field>
|
||||||
|
<field>
|
||||||
|
<name>duedate</name>
|
||||||
|
<type>timestamp</type>
|
||||||
|
<default>0</default>
|
||||||
|
</field>
|
||||||
<index>
|
<index>
|
||||||
<name>deck_cards_stack_id_index</name>
|
<name>deck_cards_stack_id_index</name>
|
||||||
<field>
|
<field>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
💥 This is still alpha software: it may not be stable enough for production!
|
💥 This is still alpha software: it may not be stable enough for production!
|
||||||
|
|
||||||
</description>
|
</description>
|
||||||
<version>0.1.4.2</version>
|
<version>0.1.4.3-1</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author>Julius Härtl</author>
|
<author>Julius Härtl</author>
|
||||||
<namespace>Deck</namespace>
|
<namespace>Deck</namespace>
|
||||||
|
|||||||
@@ -459,13 +459,45 @@ button.button-inline:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.due {
|
.due {
|
||||||
background-color: #eee;
|
|
||||||
color: #aaa;
|
|
||||||
padding: 1px 3px;
|
padding: 1px 3px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
|
font-size: 90%;
|
||||||
|
margin-left: 5px;
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
.due .icon {
|
||||||
|
background-size: contain;
|
||||||
|
float:left;
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-top:2px;
|
||||||
|
}
|
||||||
|
.overdue {
|
||||||
|
background-color: #e12419;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.due.now {
|
||||||
|
background-color: #fbd850;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.due.next {
|
||||||
|
background-color: #22ac2a;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.due .icon-calendar {
|
||||||
|
background-image: url(../img/calendar.svg);
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
.overdue .icon-calendar {
|
||||||
|
background-image: url(../img/calendar-white.svg);
|
||||||
|
}
|
||||||
|
.now .icon-calendar {
|
||||||
|
background-image: url(../img/calendar.svg);
|
||||||
|
}
|
||||||
|
.next .icon-calendar {
|
||||||
|
background-image: url(../img/calendar-white.svg);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Card view right sidebar
|
* Card view right sidebar
|
||||||
*/
|
*/
|
||||||
@@ -503,9 +535,9 @@ button.button-inline:hover {
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#card-dates span {
|
#card-meta #duedate {
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#card-description {
|
#card-description {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
54
img/calendar-white.svg
Normal file
54
img/calendar-white.svg
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
viewbox="0 0 32 32"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="calendar-white.svg"
|
||||||
|
inkscape:version="0.92.1 r">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="958"
|
||||||
|
inkscape:window-height="1054"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.375"
|
||||||
|
inkscape:cx="-8.0677966"
|
||||||
|
inkscape:cy="16"
|
||||||
|
inkscape:window-x="2880"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
d="M8 2c-1.108 0-2 .892-2 2v4c0 1.108.892 2 2 2s2-.892 2-2V4c0-1.108-.892-2-2-2zm16 0c-1.108 0-2 .892-2 2v4c0 1.108.892 2 2 2s2-.892 2-2V4c0-1.108-.892-2-2-2zM11 6v2c0 1.662-1.338 3-3 3S5 9.662 5 8V6.125A3.993 3.993 0 0 0 2 10v16c0 2.216 1.784 4 4 4h20c2.216 0 4-1.784 4-4V10a3.993 3.993 0 0 0-3-3.875V8c0 1.662-1.338 3-3 3s-3-1.338-3-3V6zM6.094 16h19.812a.09.09 0 0 1 .094.094v9.812a.09.09 0 0 1-.094.094H6.094A.09.09 0 0 1 6 25.906v-9.812A.09.09 0 0 1 6.094 16z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
1
img/calendar.svg
Normal file
1
img/calendar.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" viewbox="0 0 32 32"><path d="M8 2c-1.108 0-2 .892-2 2v4c0 1.108.892 2 2 2s2-.892 2-2V4c0-1.108-.892-2-2-2zm16 0c-1.108 0-2 .892-2 2v4c0 1.108.892 2 2 2s2-.892 2-2V4c0-1.108-.892-2-2-2zM11 6v2c0 1.662-1.338 3-3 3S5 9.662 5 8V6.125A3.993 3.993 0 0 0 2 10v16c0 2.216 1.784 4 4 4h20c2.216 0 4-1.784 4-4V10a3.993 3.993 0 0 0-3-3.875V8c0 1.662-1.338 3-3 3s-3-1.338-3-3V6zM6.094 16h19.812a.09.09 0 0 1 .094.094v9.812a.09.09 0 0 1-.094.094H6.094A.09.09 0 0 1 6 25.906v-9.812A.09.09 0 0 1 6.094 16z"/></svg>
|
||||||
|
After Width: | Height: | Size: 562 B |
@@ -14,7 +14,8 @@
|
|||||||
"angular-ui-select": "~0.19.6",
|
"angular-ui-select": "~0.19.6",
|
||||||
"angular-markdown-it": "~0.6.1",
|
"angular-markdown-it": "~0.6.1",
|
||||||
"angular-ui-router": "~1.0.0",
|
"angular-ui-router": "~1.0.0",
|
||||||
"markdown-it-link-target": "~1.0.1"
|
"markdown-it-link-target": "~1.0.1",
|
||||||
|
"jquery-timepicker": "883bb2cd94"
|
||||||
},
|
},
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
|
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
|
||||||
*
|
*
|
||||||
@@ -82,6 +80,38 @@ app.controller('CardController', function ($scope, $rootScope, $routeParams, $lo
|
|||||||
|
|
||||||
$scope.labelRemove = function (element, model) {
|
$scope.labelRemove = function (element, model) {
|
||||||
CardService.removeLabel($scope.cardId, element.id)
|
CardService.removeLabel($scope.cardId, element.id)
|
||||||
}
|
};
|
||||||
|
|
||||||
|
$scope.setDuedate = function (duedate) {
|
||||||
|
var element = CardService.getCurrent();
|
||||||
|
var newDate = moment(element.duedate);
|
||||||
|
if(!newDate.isValid()) {
|
||||||
|
newDate = moment();
|
||||||
|
}
|
||||||
|
newDate.date(duedate.date());
|
||||||
|
newDate.month(duedate.month());
|
||||||
|
newDate.year(duedate.year());
|
||||||
|
element.duedate = newDate.format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
CardService.update(element);
|
||||||
|
StackService.updateCard(element);
|
||||||
|
};
|
||||||
|
$scope.setDuedateTime = function (time) {
|
||||||
|
var element = CardService.getCurrent();
|
||||||
|
var newDate = moment(element.duedate);
|
||||||
|
if(!newDate.isValid()) {
|
||||||
|
newDate = moment();
|
||||||
|
}
|
||||||
|
newDate.hour(time.hour());
|
||||||
|
newDate.minute(time.minute());
|
||||||
|
element.duedate = newDate.format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
CardService.update(element);
|
||||||
|
StackService.updateCard(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.resetDuedate = function () {
|
||||||
|
var element = CardService.getCurrent();
|
||||||
|
element.duedate = null;
|
||||||
|
CardService.update(element);
|
||||||
|
StackService.updateCard(element);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
50
js/directive/datepicker.js
Normal file
50
js/directive/datepicker.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* @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.directive('datepicker', function () {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
link: function (scope, elm, attr) {
|
||||||
|
return elm.datepicker({
|
||||||
|
dateFormat: "yy-mm-dd",
|
||||||
|
onSelect: function(date, inst) {
|
||||||
|
scope.setDuedate(moment(date));
|
||||||
|
scope.$apply();
|
||||||
|
},
|
||||||
|
beforeShow: function(input, inst) {
|
||||||
|
var dp, marginLeft;
|
||||||
|
dp = $(inst).datepicker('widget');
|
||||||
|
marginLeft = -Math.abs($(input).outerWidth() - dp.outerWidth()) / 2 + 'px';
|
||||||
|
dp.css({
|
||||||
|
'margin-left': marginLeft
|
||||||
|
});
|
||||||
|
$("div.ui-datepicker:before").css({
|
||||||
|
'left': 100 + 'px'
|
||||||
|
});
|
||||||
|
return $('.hasDatepicker').datepicker();
|
||||||
|
},
|
||||||
|
minDate: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
41
js/directive/timepicker.js
Normal file
41
js/directive/timepicker.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* @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.directive('timepicker', function() {
|
||||||
|
'use strict';
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function(scope, elm, attr) {
|
||||||
|
return elm.timepicker({
|
||||||
|
onSelect: function(date, inst) {
|
||||||
|
scope.setDuedateTime(moment("2000-01-01 " + date));
|
||||||
|
scope.$apply();
|
||||||
|
},
|
||||||
|
myPosition: 'center top',
|
||||||
|
atPosition: 'center bottom',
|
||||||
|
hourText: t('deck', 'Hours'),
|
||||||
|
minuteText: t('deck', 'Minutes'),
|
||||||
|
showPeriodLabels: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -25,3 +25,33 @@ app.filter('relativeDateFilter', function() {
|
|||||||
return OC.Util.relativeModifiedDate(timestamp*1000);
|
return OC.Util.relativeModifiedDate(timestamp*1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.filter('relativeDateFilterString', function() {
|
||||||
|
return function (date) {
|
||||||
|
return OC.Util.relativeModifiedDate(Date.parse(date));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.filter('dateToTimestamp', function() {
|
||||||
|
return function (date) {
|
||||||
|
return Date.parse(date);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.filter('parseDate', function() {
|
||||||
|
return function (date) {
|
||||||
|
if(moment(date).isValid()) {
|
||||||
|
return moment(date).format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.filter('parseTime', function() {
|
||||||
|
return function (date) {
|
||||||
|
if(moment(date).isValid()) {
|
||||||
|
return moment(date).format('HH:mm');
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -90,8 +90,8 @@ class CardController extends Controller {
|
|||||||
* @param $description
|
* @param $description
|
||||||
* @return \OCP\AppFramework\Db\Entity
|
* @return \OCP\AppFramework\Db\Entity
|
||||||
*/
|
*/
|
||||||
public function update($id, $title, $stackId, $type, $order, $description) {
|
public function update($id, $title, $stackId, $type, $order, $description, $duedate) {
|
||||||
return $this->cardService->update($id, $title, $stackId, $type, $order, $description, $this->userId);
|
return $this->cardService->update($id, $title, $stackId, $type, $order, $description, $this->userId, $duedate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
$timeLimit = time()-(60*5);
|
$timeLimit = time()-(60*5);
|
||||||
$sql = 'SELECT id, title, owner, color, archived, deleted_at FROM `*PREFIX*deck_boards` ' .
|
$sql = 'SELECT id, title, owner, color, archived, deleted_at FROM `*PREFIX*deck_boards` ' .
|
||||||
'WHERE `deleted_at` > 0 AND `deleted_at` < ?';
|
'WHERE `deleted_at` > 0 AND `deleted_at` < ?';
|
||||||
\OC::$server->getLogger()->error($sql);
|
|
||||||
return $this->findEntities($sql, [$timeLimit]);
|
return $this->findEntities($sql, [$timeLimit]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
// db/author.php
|
// db/author.php
|
||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
|
||||||
class Card extends RelationalEntity implements JsonSerializable {
|
class Card extends RelationalEntity implements JsonSerializable {
|
||||||
@@ -39,6 +40,12 @@ class Card extends RelationalEntity implements JsonSerializable {
|
|||||||
protected $owner;
|
protected $owner;
|
||||||
protected $order;
|
protected $order;
|
||||||
protected $archived = false;
|
protected $archived = false;
|
||||||
|
protected $duedate = null;
|
||||||
|
|
||||||
|
const DUEDATE_FUTURE = 0;
|
||||||
|
const DUEDATE_NEXT = 1;
|
||||||
|
const DUEDATE_NOW = 2;
|
||||||
|
const DUEDATE_OVERDUE = 3;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->addType('id', 'integer');
|
$this->addType('id', 'integer');
|
||||||
@@ -51,4 +58,33 @@ class Card extends RelationalEntity implements JsonSerializable {
|
|||||||
$this->addResolvable('owner');
|
$this->addResolvable('owner');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() {
|
||||||
|
$json = parent::jsonSerialize();
|
||||||
|
$json['overdue'] = self::DUEDATE_FUTURE;
|
||||||
|
$due = strtotime($this->duedate);
|
||||||
|
|
||||||
|
$today = new DateTime();
|
||||||
|
$today->setTime( 0, 0, 0 );
|
||||||
|
|
||||||
|
$match_date = new DateTime($this->duedate);
|
||||||
|
|
||||||
|
$match_date->setTime( 0, 0, 0 );
|
||||||
|
|
||||||
|
$diff = $today->diff( $match_date );
|
||||||
|
$diffDays = (integer)$diff->format( "%R%a" ); // Extract days count in interval
|
||||||
|
|
||||||
|
if($due !== false) {
|
||||||
|
if ($diffDays === 1) {
|
||||||
|
$json['overdue'] = self::DUEDATE_NEXT;
|
||||||
|
}
|
||||||
|
if ($diffDays === 0) {
|
||||||
|
$json['overdue'] = self::DUEDATE_NOW;
|
||||||
|
}
|
||||||
|
if ($diffDays < 0) {
|
||||||
|
$json['overdue'] = self::DUEDATE_OVERDUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ class CardService {
|
|||||||
return $card;
|
return $card;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param integer $order
|
|
||||||
*/
|
|
||||||
public function create($title, $stackId, $type, $order, $owner) {
|
public function create($title, $stackId, $type, $order, $owner) {
|
||||||
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT);
|
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT);
|
||||||
if($this->boardService->isArchived($this->stackMapper, $stackId)) {
|
if($this->boardService->isArchived($this->stackMapper, $stackId)) {
|
||||||
@@ -76,7 +73,7 @@ class CardService {
|
|||||||
return $this->cardMapper->delete($this->cardMapper->find($id));
|
return $this->cardMapper->delete($this->cardMapper->find($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update($id, $title, $stackId, $type, $order, $description, $owner) {
|
public function update($id, $title, $stackId, $type, $order, $description, $owner, $duedate) {
|
||||||
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
|
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
|
||||||
if($this->boardService->isArchived($this->cardMapper, $id)) {
|
if($this->boardService->isArchived($this->cardMapper, $id)) {
|
||||||
throw new StatusException('Operation not allowed. This board is archived.');
|
throw new StatusException('Operation not allowed. This board is archived.');
|
||||||
@@ -91,6 +88,7 @@ class CardService {
|
|||||||
$card->setOrder($order);
|
$card->setOrder($order);
|
||||||
$card->setOwner($owner);
|
$card->setOwner($owner);
|
||||||
$card->setDescription($description);
|
$card->setDescription($description);
|
||||||
|
$card->setDuedate($duedate);
|
||||||
return $this->cardMapper->update($card);
|
return $this->cardMapper->update($card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,16 +36,17 @@ Util::addScript('deck', 'vendor/angular-ui-select/dist/select.min');
|
|||||||
Util::addScript('deck', 'vendor/markdown-it/dist/markdown-it.min');
|
Util::addScript('deck', 'vendor/markdown-it/dist/markdown-it.min');
|
||||||
Util::addScript('deck', 'vendor/angular-markdown-it/dist/ng-markdownit.min');
|
Util::addScript('deck', 'vendor/angular-markdown-it/dist/ng-markdownit.min');
|
||||||
Util::addScript('deck', 'vendor/markdown-it-link-target/dist/markdown-it-link-target.min');
|
Util::addScript('deck', 'vendor/markdown-it-link-target/dist/markdown-it-link-target.min');
|
||||||
|
Util::addScript('deck', 'vendor/jquery-timepicker/jquery.ui.timepicker');
|
||||||
|
|
||||||
if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
|
if(true && !\OC::$server->getConfig()->getSystemValue('debug', false)) {
|
||||||
Util::addScript('deck', 'public/app');
|
Util::addScript('deck', 'public/app');
|
||||||
} else {
|
} else {
|
||||||
// Load seperate JS files when debug mode is enabled
|
// Load seperate JS files when debug mode is enabled
|
||||||
$js = [
|
$js = [
|
||||||
'app' => ['App', 'Config', 'Run'],
|
'app' => ['App', 'Config', 'Run'],
|
||||||
'controller' => ['AppController', 'BoardController', 'CardController', 'ListController'],
|
'controller' => ['AppController', 'BoardController', 'CardController', 'ListController'],
|
||||||
'directive' => ['appnavigationentryutils', 'appPopoverMenuUtils', 'autofocusoninsert', 'avatar', 'elastic', 'search'],
|
'directive' => ['appnavigationentryutils', 'appPopoverMenuUtils', 'autofocusoninsert', 'avatar', 'elastic', 'search', 'datepicker', 'timepicker'],
|
||||||
'filters' => ['boardFilterAcl', 'cardFilter', 'cardSearchFilter', 'iconWhiteFilter', 'lightenColorFilter', 'orderObjectBy', 'relativeDateFilter', 'textColorFilter'],
|
'filters' => ['boardFilterAcl', 'cardFilter', 'cardSearchFilter', 'iconWhiteFilter', 'lightenColorFilter', 'orderObjectBy', 'dateFilters', 'textColorFilter'],
|
||||||
'service' => ['ApiService', 'BoardService', 'CardService', 'LabelService', 'StackService', 'StatusService'],
|
'service' => ['ApiService', 'BoardService', 'CardService', 'LabelService', 'StackService', 'StatusService'],
|
||||||
];
|
];
|
||||||
foreach($js as $folder=>$files) {
|
foreach($js as $folder=>$files) {
|
||||||
|
|||||||
@@ -68,6 +68,9 @@
|
|||||||
|
|
||||||
<div class="card-controls">
|
<div class="card-controls">
|
||||||
<i class="icon icon-filetype-text" ng-if="c.description" title="{{ c.description }}"></i>
|
<i class="icon icon-filetype-text" ng-if="c.description" title="{{ c.description }}"></i>
|
||||||
|
<span class="live-relative-timestamp due" ng-if="c.duedate"
|
||||||
|
ng-class="{'overdue': c.overdue == 3, 'now': c.overdue == 2, 'next': c.overdue == 1 }"
|
||||||
|
data-timestamp="{{ c.duedate | dateToTimestamp }}"><i class="icon icon-calendar"></i>{{ c.duedate | relativeDateFilterString }}</span>
|
||||||
<div class="app-popover-menu-utils" ng-if="!boardservice.isArchived()">
|
<div class="app-popover-menu-utils" ng-if="!boardservice.isArchived()">
|
||||||
<button class="button-inline card-options icon-more" ng-model="card"></button>
|
<button class="button-inline card-options icon-more" ng-model="card"></button>
|
||||||
<div class="popovermenu hidden">
|
<div class="popovermenu hidden">
|
||||||
|
|||||||
@@ -45,6 +45,13 @@
|
|||||||
style="background-color:#{{label.color}}; color:{{ label.color|textColorFilter }};">{{label.title}}</span>
|
style="background-color:#{{label.color}}; color:{{ label.color|textColorFilter }};">{{label.title}}</span>
|
||||||
</ui-select-choices>
|
</ui-select-choices>
|
||||||
</ui-select>
|
</ui-select>
|
||||||
|
|
||||||
|
<div id="duedate">
|
||||||
|
<input class="datepicker-input medium focus" type="text" placeholder="Set a due date" value="{{ cardservice.getCurrent().duedate | parseDate }}" datepicker="due" />
|
||||||
|
<input class="timepicker-input medium focus" type="text" placeholder="00:00:00" ng-if="cardservice.getCurrent().duedate" value="{{ cardservice.getCurrent().duedate | parseTime }}" timepicker="due" />
|
||||||
|
<button class="icon icon-delete button-inline" title="Remove duedate" ng-if="cardservice.getCurrent().duedate" ng-click="resetDuedate()"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--<div id="assigned-users">
|
<!--<div id="assigned-users">
|
||||||
|
|||||||
Reference in New Issue
Block a user