mirror of
https://github.com/wekan/wekan.git
synced 2025-12-17 16:00:13 +01:00
Merge branch 'card-spent-time' of https://github.com/thuanpq/wekan into thuanpq-card-spent-time
This commit is contained in:
commit
e162fe3c0f
12 changed files with 215 additions and 6 deletions
|
|
@ -20,6 +20,12 @@ template(name="boardList")
|
||||||
i.fa.js-star-board(
|
i.fa.js-star-board(
|
||||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||||
title="{{_ 'star-board-title'}}")
|
title="{{_ 'star-board-title'}}")
|
||||||
|
|
||||||
|
if hasSpentTimeCards
|
||||||
|
i.fa.js-has-spenttime-cards(
|
||||||
|
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||||
|
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||||
|
|
||||||
p.board-list-item-desc= description
|
p.board-list-item-desc= description
|
||||||
li.js-add-board
|
li.js-add-board
|
||||||
a.board-list-item.label {{_ 'add-board'}}
|
a.board-list-item.label {{_ 'add-board'}}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
const subManager = new SubsManager();
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
boards() {
|
boards() {
|
||||||
return Boards.find({
|
return Boards.find({
|
||||||
|
|
@ -13,6 +15,16 @@ BlazeComponent.extendComponent({
|
||||||
return user && user.hasStarred(this.currentData()._id);
|
return user && user.hasStarred(this.currentData()._id);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hasOvertimeCards() {
|
||||||
|
subManager.subscribe('board', this.currentData()._id);
|
||||||
|
return this.currentData().hasOvertimeCards();
|
||||||
|
},
|
||||||
|
|
||||||
|
hasSpentTimeCards() {
|
||||||
|
subManager.subscribe('board', this.currentData()._id);
|
||||||
|
return this.currentData().hasSpentTimeCards();
|
||||||
|
},
|
||||||
|
|
||||||
isInvited() {
|
isInvited() {
|
||||||
const user = Meteor.user();
|
const user = Meteor.user();
|
||||||
return user && user.isInvitedTo(this.currentData()._id);
|
return user && user.isInvitedTo(this.currentData()._id);
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,23 @@ $spaceBetweenTiles = 16px
|
||||||
transition-duration: .15s
|
transition-duration: .15s
|
||||||
transition-property: color, font-size, background
|
transition-property: color, font-size, background
|
||||||
|
|
||||||
|
.fa-circle
|
||||||
|
bottom: 0;
|
||||||
|
font-size: 10px;
|
||||||
|
height: 10px;
|
||||||
|
line-height: 10px;
|
||||||
|
padding: 9px 9px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transition-duration: .15s
|
||||||
|
transition-property: color, font-size, background
|
||||||
|
|
||||||
|
.has-overtime-card-active
|
||||||
|
color: #eb4646 !important
|
||||||
|
|
||||||
|
.no-overtime-card-active
|
||||||
|
color: #3cb500 !important
|
||||||
|
|
||||||
.is-star-active
|
.is-star-active
|
||||||
color: white
|
color: white
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ template(name="cardDetails")
|
||||||
h3.card-details-item-title {{_ 'card-due'}}
|
h3.card-details-item-title {{_ 'card-due'}}
|
||||||
+cardDueDate
|
+cardDueDate
|
||||||
|
|
||||||
|
.card-details-items
|
||||||
|
if spentTime
|
||||||
|
.card-details-item.card-details-item-spent
|
||||||
|
if isOvertime
|
||||||
|
h3.card-details-item-title {{_ 'overtime-hours'}}
|
||||||
|
else
|
||||||
|
h3.card-details-item-title {{_ 'spent-time-hours'}}
|
||||||
|
+cardSpentTime
|
||||||
|
|
||||||
//- XXX We should use "editable" to avoid repetiting ourselves
|
//- XXX We should use "editable" to avoid repetiting ourselves
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
|
|
@ -119,6 +127,7 @@ template(name="cardDetailsActionsPopup")
|
||||||
li: a.js-attachments {{_ 'card-edit-attachments'}}
|
li: a.js-attachments {{_ 'card-edit-attachments'}}
|
||||||
li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
||||||
li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||||
|
li: a.js-spent-time {{_ 'editCardSpentTimePopup-title'}}
|
||||||
hr
|
hr
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
|
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,7 @@ Template.cardDetailsActionsPopup.events({
|
||||||
'click .js-attachments': Popup.open('cardAttachments'),
|
'click .js-attachments': Popup.open('cardAttachments'),
|
||||||
'click .js-start-date': Popup.open('editCardStartDate'),
|
'click .js-start-date': Popup.open('editCardStartDate'),
|
||||||
'click .js-due-date': Popup.open('editCardDueDate'),
|
'click .js-due-date': Popup.open('editCardDueDate'),
|
||||||
|
'click .js-spent-time': Popup.open('editCardSpentTime'),
|
||||||
'click .js-move-card': Popup.open('moveCard'),
|
'click .js-move-card': Popup.open('moveCard'),
|
||||||
'click .js-copy-card': Popup.open('copyCard'),
|
'click .js-copy-card': Popup.open('copyCard'),
|
||||||
'click .js-move-card-to-top' (evt) {
|
'click .js-move-card-to-top' (evt) {
|
||||||
|
|
|
||||||
22
client/components/cards/cardTime.jade
Normal file
22
client/components/cards/cardTime.jade
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
template(name="editCardSpentTime")
|
||||||
|
.edit-card-time
|
||||||
|
form.edit-time
|
||||||
|
.fields
|
||||||
|
label(for="time") {{_ 'time'}}
|
||||||
|
input.js-time-field#time(type="number" step="0.01" name="time" value="{{card.spentTime}}" placeholder=timeFormat autofocus)
|
||||||
|
label(for="overtime") {{_ 'overtime'}}
|
||||||
|
a.js-toggle-overtime
|
||||||
|
.materialCheckBox#overtime(class="{{#if card.isOvertime}}is-checked{{/if}}" name="overtime")
|
||||||
|
|
||||||
|
if error.get
|
||||||
|
.warning {{_ error.get}}
|
||||||
|
button.primary.wide.left.js-submit-time(type="submit") {{_ 'save'}}
|
||||||
|
button.js-delete-time.negate.wide.right {{_ 'delete'}}
|
||||||
|
|
||||||
|
template(name="timeBadge")
|
||||||
|
if canModifyCard
|
||||||
|
a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||||
|
| {{showTime}}
|
||||||
|
else
|
||||||
|
a.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||||
|
| {{showTime}}
|
||||||
81
client/components/cards/cardTime.js
Normal file
81
client/components/cards/cardTime.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
template() {
|
||||||
|
return 'editCardSpentTime';
|
||||||
|
},
|
||||||
|
onCreated() {
|
||||||
|
this.error = new ReactiveVar('');
|
||||||
|
this.card = this.data();
|
||||||
|
},
|
||||||
|
toggleOvertime() {
|
||||||
|
this.card.isOvertime = !this.card.isOvertime;
|
||||||
|
$('#overtime .materialCheckBox').toggleClass('is-checked');
|
||||||
|
|
||||||
|
$('#overtime').toggleClass('is-checked');
|
||||||
|
},
|
||||||
|
storeTime(spentTime, isOvertime) {
|
||||||
|
this.card.setSpentTime(spentTime);
|
||||||
|
this.card.setOvertime(isOvertime);
|
||||||
|
},
|
||||||
|
deleteTime() {
|
||||||
|
this.card.unsetSpentTime();
|
||||||
|
},
|
||||||
|
events() {
|
||||||
|
return [{
|
||||||
|
//TODO : need checking this portion
|
||||||
|
'submit .edit-time'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
|
const spentTime = parseFloat(evt.target.time.value);
|
||||||
|
const isOvertime = this.card.isOvertime;
|
||||||
|
|
||||||
|
if (spentTime >= 0) {
|
||||||
|
this.storeTime(spentTime, isOvertime);
|
||||||
|
Popup.close();
|
||||||
|
} else {
|
||||||
|
this.error.set('invalid-time');
|
||||||
|
evt.target.time.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-delete-time'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
this.deleteTime();
|
||||||
|
Popup.close();
|
||||||
|
},
|
||||||
|
'click a.js-toggle-overtime': this.toggleOvertime,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
}).register('editCardSpentTimePopup');
|
||||||
|
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
template() {
|
||||||
|
return 'timeBadge';
|
||||||
|
},
|
||||||
|
onCreated() {
|
||||||
|
const self = this;
|
||||||
|
self.time = ReactiveVar();
|
||||||
|
},
|
||||||
|
showTitle() {
|
||||||
|
if (this.data().isOvertime) {
|
||||||
|
return `${TAPi18n.__('overtime')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||||
|
} else {
|
||||||
|
return `${TAPi18n.__('card-spent')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showTime() {
|
||||||
|
return this.data().spentTime;
|
||||||
|
},
|
||||||
|
isOvertime() {
|
||||||
|
return this.data().isOvertime;
|
||||||
|
},
|
||||||
|
events() {
|
||||||
|
return [{
|
||||||
|
'click .js-edit-time': Popup.open('editCardSpentTime'),
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
}).register('cardSpentTime');
|
||||||
|
|
||||||
|
Template.timeBadge.helpers({
|
||||||
|
canModifyCard() {
|
||||||
|
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||||
|
},
|
||||||
|
});
|
||||||
17
client/components/cards/cardTime.styl
Normal file
17
client/components/cards/cardTime.styl
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
.card-time
|
||||||
|
display: block
|
||||||
|
border-radius: 4px
|
||||||
|
padding: 1px 3px
|
||||||
|
color: #fff
|
||||||
|
|
||||||
|
background-color: #dbdbdb
|
||||||
|
&:hover, &.is-active
|
||||||
|
background-color: #b3b3b3
|
||||||
|
|
||||||
|
time
|
||||||
|
&::before
|
||||||
|
font: normal normal normal 14px/1 FontAwesome
|
||||||
|
font-size: inherit
|
||||||
|
-webkit-font-smoothing: antialiased
|
||||||
|
content: "\f017" // clock symbol
|
||||||
|
margin-right: 0.3em
|
||||||
|
|
@ -16,6 +16,10 @@ template(name="minicard")
|
||||||
if dueAt
|
if dueAt
|
||||||
.date
|
.date
|
||||||
+minicardDueDate
|
+minicardDueDate
|
||||||
|
if spentTime
|
||||||
|
.date
|
||||||
|
+cardSpentTime
|
||||||
|
|
||||||
if members
|
if members
|
||||||
.minicard-members.js-minicard-members
|
.minicard-members.js-minicard-members
|
||||||
each members
|
each members
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@
|
||||||
"card-delete-suggest-archive": "You can archive a card to remove it from the board and preserve the activity.",
|
"card-delete-suggest-archive": "You can archive a card to remove it from the board and preserve the activity.",
|
||||||
"card-due": "Due",
|
"card-due": "Due",
|
||||||
"card-due-on": "Due on",
|
"card-due-on": "Due on",
|
||||||
|
"card-spent": "Spent Time",
|
||||||
"card-edit-attachments": "Edit attachments",
|
"card-edit-attachments": "Edit attachments",
|
||||||
"card-edit-labels": "Edit labels",
|
"card-edit-labels": "Edit labels",
|
||||||
"card-edit-members": "Edit members",
|
"card-edit-members": "Edit members",
|
||||||
|
|
@ -175,6 +176,7 @@
|
||||||
"soft-wip-limit": "Soft WIP Limit",
|
"soft-wip-limit": "Soft WIP Limit",
|
||||||
"editCardStartDatePopup-title": "Change start date",
|
"editCardStartDatePopup-title": "Change start date",
|
||||||
"editCardDueDatePopup-title": "Change due date",
|
"editCardDueDatePopup-title": "Change due date",
|
||||||
|
"editCardSpentTimePopup-title": "Change spent time",
|
||||||
"editLabelPopup-title": "Change Label",
|
"editLabelPopup-title": "Change Label",
|
||||||
"editNotificationPopup-title": "Edit Notification",
|
"editNotificationPopup-title": "Edit Notification",
|
||||||
"editProfilePopup-title": "Edit Profile",
|
"editProfilePopup-title": "Edit Profile",
|
||||||
|
|
@ -236,6 +238,7 @@
|
||||||
"info": "Version",
|
"info": "Version",
|
||||||
"initials": "Initials",
|
"initials": "Initials",
|
||||||
"invalid-date": "Invalid date",
|
"invalid-date": "Invalid date",
|
||||||
|
"invalid-time": "Invalid time",
|
||||||
"joined": "joined",
|
"joined": "joined",
|
||||||
"just-invited": "You are just invited to this board",
|
"just-invited": "You are just invited to this board",
|
||||||
"keyboard-shortcuts": "Keyboard shortcuts",
|
"keyboard-shortcuts": "Keyboard shortcuts",
|
||||||
|
|
@ -337,6 +340,11 @@
|
||||||
"team": "Team",
|
"team": "Team",
|
||||||
"this-board": "this board",
|
"this-board": "this board",
|
||||||
"this-card": "this card",
|
"this-card": "this card",
|
||||||
|
"spent-time-hours": "Spent time (hours)",
|
||||||
|
"overtime-hours": "Overtime (hours)",
|
||||||
|
"overtime": "Overtime",
|
||||||
|
"has-overtime-cards": "Has overtime cards",
|
||||||
|
"has-spenttime-cards": "Has spenttime cards",
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"tracking": "Tracking",
|
"tracking": "Tracking",
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,16 @@ Boards.helpers({
|
||||||
return Lists.find({ boardId: this._id, archived: false }, { sort: { sort: 1 } });
|
return Lists.find({ boardId: this._id, archived: false }, { sort: { sort: 1 } });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hasOvertimeCards(){
|
||||||
|
const card = Cards.findOne({isOvertime: true, boardId: this._id, archived: false} );
|
||||||
|
return card !== undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasSpentTimeCards(){
|
||||||
|
const card = Cards.findOne({spentTime: { $gt: 0 }, boardId: this._id, archived: false} );
|
||||||
|
return card !== undefined;
|
||||||
|
},
|
||||||
|
|
||||||
activities() {
|
activities() {
|
||||||
return Activities.find({ boardId: this._id }, { sort: { createdAt: -1 } });
|
return Activities.find({ boardId: this._id }, { sort: { createdAt: -1 } });
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,16 @@ Cards.attachSchema(new SimpleSchema({
|
||||||
type: Date,
|
type: Date,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
spentTime: {
|
||||||
|
type: Number,
|
||||||
|
decimal: true,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
isOvertime: {
|
||||||
|
type: Boolean,
|
||||||
|
defaultValue: false,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
// XXX Should probably be called `authorId`. Is it even needed since we have
|
// XXX Should probably be called `authorId`. Is it even needed since we have
|
||||||
// the `members` field?
|
// the `members` field?
|
||||||
userId: {
|
userId: {
|
||||||
|
|
@ -273,6 +283,18 @@ Cards.mutations({
|
||||||
unsetDue() {
|
unsetDue() {
|
||||||
return {$unset: {dueAt: ''}};
|
return {$unset: {dueAt: ''}};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setOvertime(isOvertime) {
|
||||||
|
return {$set: {isOvertime}};
|
||||||
|
},
|
||||||
|
|
||||||
|
setSpentTime(spentTime) {
|
||||||
|
return {$set: {spentTime}};
|
||||||
|
},
|
||||||
|
|
||||||
|
unsetSpentTime() {
|
||||||
|
return {$unset: {spentTime: '', isOvertime: false}};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue