summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
Diffstat (limited to 'client/components')
-rw-r--r--client/components/boards/boardBody.jade2
-rw-r--r--client/components/boards/boardBody.js6
-rw-r--r--client/components/boards/boardHeader.jade8
-rw-r--r--client/components/boards/boardHeader.js52
-rw-r--r--client/components/cards/cardDate.jade12
-rw-r--r--client/components/cards/cardDate.js6
-rw-r--r--client/components/cards/cardDetails.jade45
-rw-r--r--client/components/cards/cardDetails.js8
-rw-r--r--client/components/cards/checklists.jade34
-rw-r--r--client/components/cards/checklists.js10
-rw-r--r--client/components/cards/minicard.jade14
-rw-r--r--client/components/cards/minicard.styl27
-rw-r--r--client/components/lists/list.js6
-rw-r--r--client/components/lists/listBody.jade2
-rw-r--r--client/components/lists/listBody.js7
-rw-r--r--client/components/lists/listHeader.jade23
-rw-r--r--client/components/main/header.js2
-rw-r--r--client/components/main/layouts.jade1
-rw-r--r--client/components/main/layouts.js2
-rw-r--r--client/components/main/layouts.styl5
-rw-r--r--client/components/settings/invitationCode.jade5
-rw-r--r--client/components/settings/invitationCode.js6
-rw-r--r--client/components/settings/settingBody.jade79
-rw-r--r--client/components/settings/settingBody.js132
-rw-r--r--client/components/settings/settingBody.styl112
-rw-r--r--client/components/settings/settingHeader.jade21
-rw-r--r--client/components/settings/settingHeader.styl25
-rw-r--r--client/components/sidebar/sidebar.jade34
-rw-r--r--client/components/sidebar/sidebar.js41
-rw-r--r--client/components/sidebar/sidebar.styl22
-rw-r--r--client/components/users/userHeader.jade2
-rw-r--r--client/components/users/userHeader.js3
32 files changed, 639 insertions, 115 deletions
diff --git a/client/components/boards/boardBody.jade b/client/components/boards/boardBody.jade
index 288590da..fe10c921 100644
--- a/client/components/boards/boardBody.jade
+++ b/client/components/boards/boardBody.jade
@@ -25,7 +25,7 @@ template(name="boardBody")
+list(this)
if currentCardIsInThisList
+cardDetails(currentCard)
- if currentUser.isBoardMember
+ if canSeeAddList
+addListForm
template(name="addListForm")
diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js
index 4703bc91..370db13b 100644
--- a/client/components/boards/boardBody.js
+++ b/client/components/boards/boardBody.js
@@ -204,3 +204,9 @@ BlazeComponent.extendComponent({
}];
},
}).register('addListForm');
+
+Template.boardBody.helpers({
+ canSeeAddList() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+});
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index 03768b36..e61aea35 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -65,7 +65,7 @@ template(name="boardHeaderBar")
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
-
+
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
@@ -81,7 +81,7 @@ template(name="boardHeaderBar")
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
- if currentUser.isBoardMember
+ if canModifyBoard
a.board-header-btn.js-multiselection-activate(
title="{{#if MultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
class="{{#if MultiSelection.isActive}}emphasis{{/if}}")
@@ -92,7 +92,7 @@ template(name="boardHeaderBar")
i.fa.fa-times-thin
.separator
- a.board-header-btn.js-open-board-menu
+ a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}")
i.board-header-btn-icon.fa.fa-navicon
template(name="boardMenuPopup")
@@ -170,7 +170,7 @@ template(name="boardChangeColorPopup")
if isSelected
i.fa.fa-check
-template(name="createBoardPopup")
+template(name="createBoard")
form
label
| {{_ 'title'}}
diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js
index a76b566a..10d9925a 100644
--- a/client/components/boards/boardHeader.js
+++ b/client/components/boards/boardHeader.js
@@ -15,17 +15,17 @@ Template.boardMenuPopup.events({
}),
});
-Template.boardMenuPopup.helpers({
- exportUrl() {
- const boardId = Session.get('currentBoard');
- const loginToken = Accounts._storedLoginToken();
- return FlowRouter.url(`api/boards/${boardId}?authToken=${loginToken}`);
- },
- exportFilename() {
- const boardId = Session.get('currentBoard');
- return `wekan-export-board-${boardId}.json`;
- },
-});
+// Template.boardMenuPopup.helpers({
+// exportUrl() {
+// const boardId = Session.get('currentBoard');
+// const loginToken = Accounts._storedLoginToken();
+// return FlowRouter.url(`api/boards/${boardId}?authToken=${loginToken}`);
+// },
+// exportFilename() {
+// const boardId = Session.get('currentBoard');
+// return `wekan-export-board-${boardId}.json`;
+// },
+// });
Template.boardChangeTitlePopup.events({
submit(evt, tpl) {
@@ -97,6 +97,12 @@ BlazeComponent.extendComponent({
},
}).register('boardHeaderBar');
+Template.boardHeaderBar.helpers({
+ canModifyBoard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+});
+
BlazeComponent.extendComponent({
backgroundColors() {
return Boards.simpleSchema()._schema.color.allowedValues;
@@ -119,10 +125,15 @@ BlazeComponent.extendComponent({
},
}).register('boardChangeColorPopup');
-BlazeComponent.extendComponent({
+const CreateBoard = BlazeComponent.extendComponent({
+ template() {
+ return 'createBoard';
+ },
+
onCreated() {
this.visibilityMenuIsOpen = new ReactiveVar(false);
this.visibility = new ReactiveVar('private');
+ this.boardId = new ReactiveVar('');
},
visibilityCheck() {
@@ -143,15 +154,12 @@ BlazeComponent.extendComponent({
const title = this.find('.js-new-board-title').value;
const visibility = this.visibility.get();
- const boardId = Boards.insert({
+ this.boardId.set(Boards.insert({
title,
permission: visibility,
- });
-
- Utils.goBoardId(boardId);
+ }));
- // Immediately star boards crated with the headerbar popup.
- Meteor.user().toggleBoardStar(boardId);
+ Utils.goBoardId(this.boardId.get());
},
events() {
@@ -166,6 +174,14 @@ BlazeComponent.extendComponent({
},
}).register('createBoardPopup');
+(class HeaderBarCreateBoard extends CreateBoard {
+ onSubmit(evt) {
+ super.onSubmit(evt);
+ // Immediately star boards crated with the headerbar popup.
+ Meteor.user().toggleBoardStar(this.boardId.get());
+ }
+}).register('headerBarCreateBoardPopup');
+
BlazeComponent.extendComponent({
visibilityCheck() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
diff --git a/client/components/cards/cardDate.jade b/client/components/cards/cardDate.jade
index a2a28bbd..525f27ed 100644
--- a/client/components/cards/cardDate.jade
+++ b/client/components/cards/cardDate.jade
@@ -15,6 +15,12 @@ template(name="editCardDate")
button.js-delete-date.negate.wide.right.js-delete-date {{_ 'delete'}}
template(name="dateBadge")
- a.js-edit-date.card-date(title="{{showTitle}}" class="{{classes}}")
- time(datetime="{{showISODate}}")
- | {{showDate}}
+ if canModifyCard
+ a.js-edit-date.card-date(title="{{showTitle}}" class="{{classes}}")
+ time(datetime="{{showISODate}}")
+ | {{showDate}}
+ else
+ a.card-date(title="{{showTitle}}" class="{{classes}}")
+ time(datetime="{{showISODate}}")
+ | {{showDate}}
+
diff --git a/client/components/cards/cardDate.js b/client/components/cards/cardDate.js
index 4d129e8e..3f69f384 100644
--- a/client/components/cards/cardDate.js
+++ b/client/components/cards/cardDate.js
@@ -86,6 +86,12 @@ const EditCardDate = BlazeComponent.extendComponent({
},
});
+Template.dateBadge.helpers({
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+});
+
// editCardStartDatePopup
(class extends EditCardDate {
onCreated() {
diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade
index cf113951..9c95e92f 100644
--- a/client/components/cards/cardDetails.jade
+++ b/client/components/cards/cardDetails.jade
@@ -8,7 +8,7 @@ template(name="cardDetails")
if currentUser.isBoardMember
a.fa.fa-navicon.card-details-menu.js-open-card-details-menu
h2.card-details-title.js-card-title(
- class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
+ class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
= title
if isWatching
i.fa.fa-eye.card-details-watch
@@ -22,16 +22,16 @@ template(name="cardDetails")
each members
+userAvatar(userId=this cardId=../_id)
| {{! XXX Hack to hide syntaxic coloration /// }}
- if currentUser.isBoardMember
+ if canModifyCard
a.member.add-member.card-details-item-add-button.js-add-members(title="{{_ 'card-members-title'}}")
i.fa.fa-plus
.card-details-item.card-details-item-labels
h3.card-details-item-title {{_ 'labels'}}
- a(class="{{#if currentUser.isBoardMember}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
+ a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
each labels
span.card-label(class="card-label-{{color}}" title=name)= name
- if currentUser.isBoardMember
+ if canModifyCard
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
i.fa.fa-plus
@@ -47,7 +47,7 @@ template(name="cardDetails")
//- XXX We should use "editable" to avoid repetiting ourselves
- if currentUser.isBoardMember
+ if canModifyCard
h3.card-details-item-title {{_ 'description'}}
+inlinedCardDescription(classNames="card-description js-card-description")
+editor(autofocus=true)
@@ -101,23 +101,24 @@ template(name="editCardTitleForm")
template(name="cardDetailsActionsPopup")
ul.pop-over-list
li: a.js-toggle-watch-card {{#if isWatching}}{{_ 'unwatch'}}{{else}}{{_ 'watch'}}{{/if}}
- hr
- ul.pop-over-list
- li: a.js-members {{_ 'card-edit-members'}}
- li: a.js-labels {{_ 'card-edit-labels'}}
- li: a.js-attachments {{_ 'card-edit-attachments'}}
- li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
- li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
- hr
- ul.pop-over-list
- li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
- li: a.js-move-card-to-bottom {{_ 'moveCardToBottom-title'}}
- hr
- ul.pop-over-list
- li: a.js-move-card {{_ 'moveCardPopup-title'}}
- unless archived
- li: a.js-archive {{_ 'archive-card'}}
- li: a.js-more {{_ 'cardMorePopup-title'}}
+ if canModifyCard
+ hr
+ ul.pop-over-list
+ li: a.js-members {{_ 'card-edit-members'}}
+ li: a.js-labels {{_ 'card-edit-labels'}}
+ li: a.js-attachments {{_ 'card-edit-attachments'}}
+ li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
+ li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
+ hr
+ ul.pop-over-list
+ li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
+ li: a.js-move-card-to-bottom {{_ 'moveCardToBottom-title'}}
+ hr
+ ul.pop-over-list
+ li: a.js-move-card {{_ 'moveCardPopup-title'}}
+ unless archived
+ li: a.js-archive {{_ 'archive-card'}}
+ li: a.js-more {{_ 'cardMorePopup-title'}}
template(name="moveCardPopup")
+boardLists
diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js
index b7e0ef76..b39f8e59 100644
--- a/client/components/cards/cardDetails.js
+++ b/client/components/cards/cardDetails.js
@@ -28,6 +28,10 @@ BlazeComponent.extendComponent({
return card.findWatcher(Meteor.userId());
},
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+
scrollParentContainer() {
const cardPanelWidth = 510;
const bodyBoardComponent = this.parentComponent();
@@ -140,6 +144,10 @@ Template.cardDetailsActionsPopup.helpers({
isWatching() {
return this.findWatcher(Meteor.userId());
},
+
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
});
Template.cardDetailsActionsPopup.events({
diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade
index 987e6cd9..a0d89351 100644
--- a/client/components/cards/checklists.jade
+++ b/client/components/cards/checklists.jade
@@ -3,12 +3,13 @@ template(name="checklists")
.card-checklist-items
each checklist in currentCard.checklists
+checklistDetail(checklist = checklist)
- +inlinedForm(classNames="js-add-checklist" cardId = cardId)
- +addChecklistItemForm
- else
- a.js-open-inlined-form
- i.fa.fa-plus
- | {{_ 'add-checklist'}}...
+ if canModifyCard
+ +inlinedForm(classNames="js-add-checklist" cardId = cardId)
+ +addChecklistItemForm
+ else
+ a.js-open-inlined-form
+ i.fa.fa-plus
+ | {{_ 'add-checklist'}}...
template(name="checklistDetail")
+inlinedForm(classNames="js-edit-checklist-title" checklist = checklist)
@@ -16,9 +17,13 @@ template(name="checklistDetail")
else
.checklist-title
.checkbox.fa.fa-check-square-o
- a.js-delete-checklist {{_ "delete"}}...
+ if canModifyCard
+ a.js-delete-checklist {{_ "delete"}}...
span.checklist-stat(class="{{#if checklist.isFinished}}is-finished{{/if}}") {{checklist.finishedCount}}/{{checklist.itemCount}}
- h2.title.js-open-inlined-form.is-editable {{checklist.title}}
+ if canModifyCard
+ h2.title.js-open-inlined-form.is-editable {{checklist.title}}
+ else
+ h2.title {{checklist.title}}
+checklistItems(checklist = checklist)
template(name="addChecklistItemForm")
@@ -37,7 +42,7 @@ template(name="editChecklistItemForm")
button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
span(title=createdAt) {{ moment createdAt }}
- if currentUser.isBoardMember
+ if canModifyCard
a.js-delete-checklist-item {{_ "delete"}}...
template(name="checklistItems")
@@ -47,7 +52,7 @@ template(name="checklistItems")
+editChecklistItemForm(type = 'item' item = item checklist = checklist)
else
+itemDetail(item = item checklist = checklist)
- if currentUser.isBoardMember
+ if canModifyCard
+inlinedForm(classNames="js-add-checklist-item" checklist = checklist)
+addChecklistItemForm
else
@@ -57,5 +62,10 @@ template(name="checklistItems")
template(name='itemDetail')
.item
- .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
- .item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
+ if canModifyCard
+ .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
+ .item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
+ else
+ .materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
+ .item-title(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
+
diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js
index 5dac7bd3..b8f5e443 100644
--- a/client/components/cards/checklists.js
+++ b/client/components/cards/checklists.js
@@ -26,6 +26,10 @@ BlazeComponent.extendComponent({
checklist.setTitle(title);
},
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+
editChecklistItem(event) {
event.preventDefault();
@@ -73,6 +77,12 @@ BlazeComponent.extendComponent({
},
}).register('checklists');
+Template.itemDetail.helpers({
+ canModifyCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+});
+
BlazeComponent.extendComponent({
toggleItem() {
const checklist = this.currentData().checklist;
diff --git a/client/components/cards/minicard.jade b/client/components/cards/minicard.jade
index 8b46ee74..5409ec62 100644
--- a/client/components/cards/minicard.jade
+++ b/client/components/cards/minicard.jade
@@ -7,6 +7,13 @@ template(name="minicard")
each labels
.minicard-label(class="card-label-{{color}}" title="{{name}}")
.minicard-title= title
+ .dates
+ if startAt
+ .date
+ +minicardStartDate
+ if dueAt
+ .date
+ +minicardDueDate
if members
.minicard-members.js-minicard-members
each members
@@ -23,14 +30,7 @@ template(name="minicard")
.badge
span.badge-icon.fa.fa-paperclip
span.badge-text= attachments.count
- if startAt
- .badge
- +minicardStartDate
- if dueAt
- .badge
- +minicardDueDate
if checklists.count
.badge(class="{{#if checklistFinished}}is-finished{{/if}}")
span.badge-icon.fa.fa-check-square-o
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
-
diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl
index 12a89785..a6aad896 100644
--- a/client/components/cards/minicard.styl
+++ b/client/components/cards/minicard.styl
@@ -77,7 +77,12 @@
height: @width
border-radius: 2px
margin-left: 3px
-
+ .dates
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ .date
+ margin-right: 3px
.badges
float: left
margin-top: 7px
@@ -91,25 +96,20 @@
margin-right: 11px
margin-bottom: 3px
font-size: 0.9em
-
+ &.is-finished
+ background: #3cb500
+ padding: 0px 3px
+ border-radius: 3px
+ color: white
+
&:last-of-type
margin-right: 0
.badge-icon,
.badge-text
vertical-align: middle
-
- &.is-finished
- background: #3cb500
- padding: 0px 3px
- border-radius: 3px
- color: white
-
- .badge-icon,
- .badge-text
- vertical-align: middle//didn't figure why use top, it'd be easier to fill bg if it's middle. This was introduced in commit "91cfcf7b12b5e7c137c2e765b2c378dde6b82966" & "* Improve the design of the minicards badges" was mentioned.
&.badge-comment
- margin-bottom: 0.1rem
+ margin-bottom: 0.1rem
.badge-text
font-size: 0.9em
@@ -119,7 +119,6 @@
padding-left: 0px
line-height: 12px
-
.minicard-members
float: right
margin: 2px -8px -2px 0
diff --git a/client/components/lists/list.js b/client/components/lists/list.js
index e1909783..9c191348 100644
--- a/client/components/lists/list.js
+++ b/client/components/lists/list.js
@@ -44,7 +44,7 @@ BlazeComponent.extendComponent({
placeholder: 'minicard-wrapper placeholder',
start(evt, ui) {
ui.placeholder.height(ui.helper.height());
- EscapeActions.executeUpTo('popup');
+ EscapeActions.executeUpTo('popup-close');
boardComponent.setIsDragging(true);
},
stop(evt, ui) {
@@ -79,10 +79,10 @@ BlazeComponent.extendComponent({
});
function userIsMember() {
- return Meteor.user() && Meteor.user().isBoardMember();
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
}
- // Disable drag-dropping if the current user is not a board member
+ // Disable drag-dropping if the current user is not a board member or is comment only
this.autorun(() => {
$cards.sortable('option', 'disabled', !userIsMember());
});
diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade
index e659b179..01aa7179 100644
--- a/client/components/lists/listBody.jade
+++ b/client/components/lists/listBody.jade
@@ -12,7 +12,7 @@ template(name="listBody")
.materialCheckBox.multi-selection-checkbox.js-toggle-multi-selection(
class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}")
+minicard(this)
- if currentUser.isBoardMember
+ if canSeeAddCard
+inlinedForm(autoclose=false position="bottom")
+addCardForm(listId=_id position="bottom")
else
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js
index 34c2dcd6..bdc812c7 100644
--- a/client/components/lists/listBody.js
+++ b/client/components/lists/listBody.js
@@ -239,3 +239,10 @@ BlazeComponent.extendComponent({
});
},
}).register('addCardForm');
+
+
+Template.listBody.helpers({
+ canSeeAddCard() {
+ return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
+ },
+});
diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade
index 81afebe1..11905586 100644
--- a/client/components/lists/listHeader.jade
+++ b/client/components/lists/listHeader.jade
@@ -25,17 +25,18 @@ template(name="editListTitleForm")
template(name="listActionPopup")
ul.pop-over-list
li: a.js-toggle-watch-list {{#if isWatching}}{{_ 'unwatch'}}{{else}}{{_ 'watch'}}{{/if}}
- hr
- ul.pop-over-list
- li: a.js-add-card {{_ 'add-card'}}
- if cards.count
- li: a.js-select-cards {{_ 'list-select-cards'}}
- hr
- ul.pop-over-list
- li: a.js-close-list {{_ 'archive-list'}}
- hr
- ul.pop-over-list
- li: a.js-more {{_ 'listMorePopup-title'}}
+ unless currentUser.isCommentOnly
+ hr
+ ul.pop-over-list
+ li: a.js-add-card {{_ 'add-card'}}
+ if cards.count
+ li: a.js-select-cards {{_ 'list-select-cards'}}
+ hr
+ ul.pop-over-list
+ li: a.js-close-list {{_ 'archive-list'}}
+ hr
+ ul.pop-over-list
+ li: a.js-more {{_ 'listMorePopup-title'}}
template(name="boardLists")
ul.pop-over-list
diff --git a/client/components/main/header.js b/client/components/main/header.js
index 0337c72b..49acbfef 100644
--- a/client/components/main/header.js
+++ b/client/components/main/header.js
@@ -13,5 +13,5 @@ Template.header.helpers({
});
Template.header.events({
- 'click .js-create-board': Popup.open('createBoard'),
+ 'click .js-create-board': Popup.open('headerBarCreateBoard'),
});
diff --git a/client/components/main/layouts.jade b/client/components/main/layouts.jade
index 943ebe0f..12fac0a8 100644
--- a/client/components/main/layouts.jade
+++ b/client/components/main/layouts.jade
@@ -2,6 +2,7 @@ head
title Wekan
meta(name="viewport"
content="maximum-scale=1.0,width=device-width,initial-scale=1.0,user-scalable=0")
+ meta(http-equiv="X-UA-Compatible" content="IE=edge")
//- XXX We should use pathFor in the following `href` to support the case
where the application is deployed with a path prefix, but it seems to be
difficult to do that cleanly with Blaze -- at least without adding extra
diff --git a/client/components/main/layouts.js b/client/components/main/layouts.js
index 3df17f41..1e50b01a 100644
--- a/client/components/main/layouts.js
+++ b/client/components/main/layouts.js
@@ -1,4 +1,6 @@
Meteor.subscribe('boards');
+Meteor.subscribe('setting');
+Meteor.subscribe('user-admin');
BlazeLayout.setRoot('body');
diff --git a/client/components/main/layouts.styl b/client/components/main/layouts.styl
index 38fd83ec..349ee743 100644
--- a/client/components/main/layouts.styl
+++ b/client/components/main/layouts.styl
@@ -351,6 +351,11 @@ a
background: darken(white, 13%)
overflow-y: auto
+ a
+ text-decoration: underline
+ &:hover
+ color: #333
+
.basicTabs-container .tabs-content-container
padding: 0
padding-top: 15px
diff --git a/client/components/settings/invitationCode.jade b/client/components/settings/invitationCode.jade
new file mode 100644
index 00000000..171a2663
--- /dev/null
+++ b/client/components/settings/invitationCode.jade
@@ -0,0 +1,5 @@
+template(name='invitationCode')
+ .at-input#invitationcode
+ label(for='at-field-code') {{_ 'invitation-code'}}
+
+ input#at-field-invitationcode(type="text" name='at-field-invitationcode' placeholder="{{_ 'invitation-code'}}")
diff --git a/client/components/settings/invitationCode.js b/client/components/settings/invitationCode.js
new file mode 100644
index 00000000..a403d8ab
--- /dev/null
+++ b/client/components/settings/invitationCode.js
@@ -0,0 +1,6 @@
+Template.invitationCode.onRendered(() => {
+ const setting = Settings.findOne();
+ if (!setting || !setting.disableRegistration) {
+ $('#invitationcode').hide();
+ }
+});
diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade
new file mode 100644
index 00000000..d490ec93
--- /dev/null
+++ b/client/components/settings/settingBody.jade
@@ -0,0 +1,79 @@
+template(name="setting")
+ .setting-content
+ .content-title
+ span {{_ 'settings'}}
+ .content-body
+ .side-menu
+ ul
+ li.active
+ a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
+ li
+ a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
+ .main-body
+ if loading.get
+ +spinner
+ else if generalSetting.get
+ +general
+ else if emailSetting.get
+ +email
+
+template(name="general")
+ ul#registration-setting.setting-detail
+ li
+ a.flex.js-toggle-registration
+ .materialCheckBox(class="{{#if currentSetting.disableRegistration}}is-checked{{/if}}")
+
+ span {{_ 'disable-self-registration'}}
+ li
+ .invite-people(class="{{#if currentSetting.disableRegistration}}{{else}}hide{{/if}}")
+ ul
+ li
+ .title {{_ 'invite-people'}}
+ textarea#email-to-invite.form-control(rows='5', placeholder="{{_ 'email-addresses'}}")
+ li
+ .title {{_ 'to-boards'}}
+ .bg-white
+ each boards
+ a.option.flex.js-toggle-board-choose(id= _id)
+ .materialCheckBox(data-id= _id)
+
+ span= title
+
+ li
+ button.js-email-invite.primary {{_ 'invite'}}
+
+template(name='email')
+ ul#email-setting.setting-detail
+ li.smtp-form
+ .title {{_ 'smtp-host'}}
+ .description {{_ 'smtp-host-description'}}
+ .form-group
+ input.form-control#mail-server-host(type="text", placeholder="smtp.domain.com" value="{{currentSetting.mailServer.host}}")
+ li.smtp-form
+ .title {{_ 'smtp-port'}}
+ .description {{_ 'smtp-port-description'}}
+ .form-group
+ input.form-control#mail-server-port(type="text", placeholder="25" value="{{currentSetting.mailServer.port}}")
+ li.smtp-form
+ .title {{_ 'smtp-username'}}
+ .form-group
+ input.form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
+ li.smtp-form
+ .title {{_ 'smtp-password'}}
+ .form-group
+ input.form-control#mail-server-password(type="text", placeholder="{{_ 'password'}}" value="{{currentSetting.mailServer.password}}")
+ li.smtp-form
+ .title {{_ 'smtp-tls'}}
+ .form-group
+ a.flex.js-toggle-tls
+ .materialCheckBox#mail-server-tls(class="{{#if currentSetting.mailServer.enableTLS}}is-checked{{/if}}")
+
+ span {{_ 'smtp-tls-description'}}
+
+ li.smtp-form
+ .title {{_ 'send-from'}}
+ .form-group
+ input.form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
+
+ li
+ button.js-save.primary Save
diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js
new file mode 100644
index 00000000..f96312a5
--- /dev/null
+++ b/client/components/settings/settingBody.js
@@ -0,0 +1,132 @@
+Meteor.subscribe('setting');
+Meteor.subscribe('mailServer');
+
+BlazeComponent.extendComponent({
+ onCreated() {
+ this.error = new ReactiveVar('');
+ this.loading = new ReactiveVar(false);
+ this.generalSetting = new ReactiveVar(true);
+ this.emailSetting = new ReactiveVar(false);
+ },
+
+ setError(error) {
+ this.error.set(error);
+ },
+
+ setLoading(w) {
+ this.loading.set(w);
+ },
+
+ checkField(selector) {
+ const value = $(selector).val();
+ if(!value || value.trim() === ''){
+ $(selector).parents('li.smtp-form').addClass('has-error');
+ throw Error('blank field');
+ } else {
+ return value;
+ }
+ },
+
+ currentSetting(){
+ return Settings.findOne();
+ },
+
+ boards() {
+ return Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ 'members.isAdmin': true,
+ }, {
+ sort: ['title'],
+ });
+ },
+ toggleRegistration(){
+ this.setLoading(true);
+ const registrationClosed = this.currentSetting().disableRegistration;
+ Settings.update(Settings.findOne()._id, {$set:{disableRegistration: !registrationClosed}});
+ this.setLoading(false);
+ if(registrationClosed){
+ $('.invite-people').slideUp();
+ }else{
+ $('.invite-people').slideDown();
+ }
+ },
+ toggleTLS(){
+ $('#mail-server-tls').toggleClass('is-checked');
+ },
+ switchMenu(event){
+ const target = $(event.target);
+ if(!target.hasClass('active')){
+ $('.side-menu li.active').removeClass('active');
+ target.parent().addClass('active');
+ const targetID = target.data('id');
+ this.generalSetting.set('registration-setting' === targetID);
+ this.emailSetting.set('email-setting' === targetID);
+ }
+ },
+
+ checkBoard(event){
+ let target = $(event.target);
+ if(!target.hasClass('js-toggle-board-choose')){
+ target = target.parent();
+ }
+ const checkboxId = target.attr('id');
+ $(`#${checkboxId} .materialCheckBox`).toggleClass('is-checked');
+ $(`#${checkboxId}`).toggleClass('is-checked');
+ },
+
+ inviteThroughEmail(){
+ const emails = $('#email-to-invite').val().trim().split('\n').join(',').split(',');
+ const boardsToInvite = [];
+ $('.js-toggle-board-choose .materialCheckBox.is-checked').each(function () {
+ boardsToInvite.push($(this).data('id'));
+ });
+ const validEmails = [];
+ emails.forEach((email) => {
+ if (email && SimpleSchema.RegEx.Email.test(email.trim())) {
+ validEmails.push(email.trim());
+ }
+ });
+ if (validEmails.length) {
+ this.setLoading(true);
+ Meteor.call('sendInvitation', validEmails, boardsToInvite, () => {
+ // if (!err) {
+ // TODO - show more info to user
+ // }
+ this.setLoading(false);
+ });
+ }
+ },
+
+ saveMailServerInfo(){
+ this.setLoading(true);
+ $('li').removeClass('has-error');
+
+ try{
+ const host = this.checkField('#mail-server-host');
+ const port = this.checkField('#mail-server-port');
+ const username = $('#mail-server-username').val().trim();
+ const password = $('#mail-server-password').val().trim();
+ const from = this.checkField('#mail-server-from');
+ const tls = $('#mail-server-tls.is-checked').length > 0;
+ Settings.update(Settings.findOne()._id, {$set:{'mailServer.host':host, 'mailServer.port': port, 'mailServer.username': username,
+ 'mailServer.password': password, 'mailServer.enableTLS': tls, 'mailServer.from': from}});
+ } catch (e) {
+ return;
+ } finally {
+ this.setLoading(false);
+ }
+
+ },
+
+ events(){
+ return [{
+ 'click a.js-toggle-registration': this.toggleRegistration,
+ 'click a.js-toggle-tls': this.toggleTLS,
+ 'click a.js-setting-menu': this.switchMenu,
+ 'click a.js-toggle-board-choose': this.checkBoard,
+ 'click button.js-email-invite': this.inviteThroughEmail,
+ 'click button.js-save': this.saveMailServerInfo,
+ }];
+ },
+}).register('setting');
diff --git a/client/components/settings/settingBody.styl b/client/components/settings/settingBody.styl
new file mode 100644
index 00000000..118d364c
--- /dev/null
+++ b/client/components/settings/settingBody.styl
@@ -0,0 +1,112 @@
+.flex
+ display: -webkit-box
+ display: -moz-box
+ display: -webkit-flex
+ display: -moz-flex
+ display: -ms-flexbox
+ display: flex
+
+.setting-content
+ padding 30px
+ color: #727479
+ background: #dedede
+ width 100%
+ height 100%
+ position: absolute;
+
+ .content-title
+ font-size 20px
+
+ .content-body
+ display flex
+ padding-top 15px
+ height 100%
+
+ .side-menu
+ background-color: #f7f7f7;
+ border: 1px solid #f0f0f0;
+ border-radius: 4px;
+ width: 250px;
+ box-shadow: inset -1px -1px 3px rgba(0,0,0,.05);
+
+ ul
+
+ li
+ margin: 0.1rem 0.2rem;
+
+ &.active
+ background #fff
+ box-shadow 0 1px 2px rgba(0,0,0,0.15);
+
+ &:hover
+ background #fff
+ box-shadow 0 1px 2px rgba(0,0,0,0.15);
+ a
+ @extends .flex
+ padding: 1rem 0 1rem 1rem
+ width: 100% - 5rem
+
+
+ span
+ font-size: 13px
+
+ .main-body
+ padding: 0.1em 1em
+
+ ul
+ li
+ padding: 0.5rem 0.5rem;
+
+ a
+ .is-checked
+ border-bottom: 2px solid #2980b9;
+ border-right: 2px solid #2980b9;
+
+ span
+ padding: 0 0.5rem
+
+ .invite-people
+ padding-left 20px;
+ li
+ min-width: 500px;
+
+ ul.no-margin-bottom
+ margin-bottom: 0;
+
+ .bg-white
+ a
+ background #f7f7f7
+ &.is-checked
+ background #fff
+
+
+.option
+ @extends .flex
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: #fff;
+ text-decoration: none;
+ -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
+ box-shadow: 0 1px 2px rgba(0,0,0,0.2);
+ margin-top: 5px;
+ padding: 5px;
+
+.title
+ font-weight 700;
+ margin-bottom 0.5rem;
+.description
+ margin-bottom 0.5rem;
+.bg-white
+ background #f9fbfc;
+
+.form-control.has-error
+ border-color: #a94442;
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+
+li.has-error
+ color #a94442
+ .form-group
+ .form-control
+ border-color: #a94442;
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+
diff --git a/client/components/settings/settingHeader.jade b/client/components/settings/settingHeader.jade
new file mode 100644
index 00000000..fb884056
--- /dev/null
+++ b/client/components/settings/settingHeader.jade
@@ -0,0 +1,21 @@
+template(name="settingHeaderBar")
+ h1.header-setting-menu
+ span {{_ 'admin-panel'}}
+
+ .setting-header-btns.left
+ unless isMiniScreen
+ unless isSandstorm
+ if currentUser
+ a.setting-header-btn.settings.active
+ i.fa(class="fa-cog")
+ span {{_ 'settings'}}
+//TODO
+// a.setting-header-btn.people
+// i.fa(class="fa-users")
+// span {{_ 'people'}}
+
+ else
+ a.setting-header-btn.js-log-in(
+ title="{{_ 'log-in'}}")
+ i.fa.fa-sign-in
+ span {{_ 'log-in'}}
diff --git a/client/components/settings/settingHeader.styl b/client/components/settings/settingHeader.styl
new file mode 100644
index 00000000..995ed26d
--- /dev/null
+++ b/client/components/settings/settingHeader.styl
@@ -0,0 +1,25 @@
+#header #header-main-bar .setting-header-btn
+ &.active,
+ &:hover:not(.is-disabled)
+ background: rgba(0, 0, 0, .15)
+ color: darken(white, 5%)
+ margin-left: 20px;
+ padding-right: 10px;
+ height: 28px;
+ font-size: 13px;
+ float: left;
+ overflow: hidden;
+ line-height: @height;
+ margin: 0 2px;
+
+ i.fa
+ float: left
+ display: block
+ line-height: 28px
+ color: darken(white, 5%)
+ margin: 0 10px
+
+ + span
+ display: inline-block
+ margin-top: 1px
+ margin-right: 10px \ No newline at end of file
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index f3fdd1bc..6045b371 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -1,16 +1,22 @@
template(name="sidebar")
.board-sidebar.sidebar(class="{{#if isOpen}}is-open{{/if}}")
a.sidebar-tongue.js-toggle-sidebar(
- class="{{#if isTongueHidden}}is-hidden{{/if}}")
+ class="{{#if isTongueHidden}}is-hidden{{/if}}",
+ title="{{showTongueTitle}}")
i.fa.fa-angle-left
- .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar
- a.hide-btn.js-hide-sidebar
- i.fa.fa-angle-right
- unless isDefaultView
- h2
- a.fa.fa-chevron-left.js-back-home
- = getViewTitle
- +Template.dynamic(template=getViewTemplate)
+ .sidebar-shadow
+ .sidebar-content.sidebar-shortcuts
+ a.board-header-btn.js-shortcuts
+ i.fa.fa-keyboard-o
+ span {{_ 'keyboard-shortcuts' }}
+ .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar
+ a.hide-btn.js-hide-sidebar
+ i.fa.fa-angle-right
+ unless isDefaultView
+ h2
+ a.fa.fa-chevron-left.js-back-home
+ = getViewTitle
+ +Template.dynamic(template=getViewTemplate)
template(name='homeSidebar')
+membersWidget
@@ -54,7 +60,7 @@ template(name="labelsWidget")
.board-widget-content
each currentBoard.labels
a.card-label(class="card-label-{{color}}"
- class="{{#if currentUser.isBoardMember}}js-label{{/if}}")
+ class="{{#if currentUser.isNotCommentOnly}}js-label{{/if}}")
span.card-label-name= name
if currentUser.isBoardAdmin
a.card-label.add-label.js-add-label
@@ -132,9 +138,15 @@ template(name="changePermissionsPopup")
li
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-normal{{/if}}")
| {{_ 'normal'}}
- unless isAdmin
+ if isNormal
i.fa.fa-check
span.sub-name {{_ 'normal-desc'}}
+ li
+ a(class="{{#if isLastAdmin}}disabled{{else}}js-set-comment-only{{/if}}")
+ | {{_ 'comment-only'}}
+ if isCommentOnly
+ i.fa.fa-check
+ span.sub-name {{_ 'comment-only-desc'}}
if isLastAdmin
hr
p.quiet.bottom {{_ 'last-admin-desc'}}
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index f32a27c5..1290fd13 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -89,11 +89,21 @@ BlazeComponent.extendComponent({
return TAPi18n.__(viewTitles[this.getView()]);
},
+ showTongueTitle() {
+ if (this.isOpen())
+ return `${TAPi18n.__('sidebar-close')}`;
+ else
+ return `${TAPi18n.__('sidebar-open')}`;
+ },
+
events() {
return [{
'click .js-hide-sidebar': this.hide,
'click .js-toggle-sidebar': this.toggle,
'click .js-back-home': this.setView,
+ 'click .js-shortcuts'() {
+ FlowRouter.go('shortcuts');
+ },
}];
},
}).register('sidebar');
@@ -111,7 +121,17 @@ Template.memberPopup.helpers({
},
memberType() {
const type = Users.findOne(this.userId).isBoardAdmin() ? 'admin' : 'normal';
- return TAPi18n.__(type).toLowerCase();
+ if(type === 'normal'){
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ const commentOnly = currentBoard.hasCommentOnly(this.userId);
+ if(commentOnly){
+ return TAPi18n.__('comment-only').toLowerCase();
+ } else {
+ return TAPi18n.__(type).toLowerCase();
+ }
+ } else {
+ return TAPi18n.__(type).toLowerCase();
+ }
},
isInvited() {
return Users.findOne(this.userId).isInvitedTo(Session.get('currentBoard'));
@@ -134,8 +154,8 @@ Template.memberPopup.events({
Popup.close();
}),
'click .js-leave-member'() {
- const currentBoard = Boards.findOne(Session.get('currentBoard'));
- Meteor.call('quitBoard', currentBoard, (err, ret) => {
+ const boardId = Session.get('currentBoard');
+ Meteor.call('quitBoard', boardId, (err, ret) => {
if (!ret && ret) {
Popup.close();
FlowRouter.go('home');
@@ -298,11 +318,12 @@ BlazeComponent.extendComponent({
}).register('addMemberPopup');
Template.changePermissionsPopup.events({
- 'click .js-set-admin, click .js-set-normal'(event) {
+ 'click .js-set-admin, click .js-set-normal, click .js-set-comment-only'(event) {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const memberId = this.userId;
const isAdmin = $(event.currentTarget).hasClass('js-set-admin');
- currentBoard.setMemberPermission(memberId, isAdmin);
+ const isCommentOnly = $(event.currentTarget).hasClass('js-set-comment-only');
+ currentBoard.setMemberPermission(memberId, isAdmin, isCommentOnly);
Popup.back(1);
},
});
@@ -313,6 +334,16 @@ Template.changePermissionsPopup.helpers({
return currentBoard.hasAdmin(this.userId);
},
+ isNormal() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ return !currentBoard.hasAdmin(this.userId) && !currentBoard.hasCommentOnly(this.userId);
+ },
+
+ isCommentOnly() {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ return !currentBoard.hasAdmin(this.userId) && currentBoard.hasCommentOnly(this.userId);
+ },
+
isLastAdmin() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
return currentBoard.hasAdmin(this.userId) && (currentBoard.activeAdmins() === 1);
diff --git a/client/components/sidebar/sidebar.styl b/client/components/sidebar/sidebar.styl
index 24abe990..8f2f493e 100644
--- a/client/components/sidebar/sidebar.styl
+++ b/client/components/sidebar/sidebar.styl
@@ -6,11 +6,19 @@
bottom: 0
right: 0
- .sidebar-content
- padding: 12px
+ .sidebar-shadow
+ position: absolute
+ top: 0
+ bottom: 0
+ right: 0
+ left: 0
background: darken(white, 3%)
box-shadow: -10px 0px 5px -10px darken(white, 30%)
z-index: 10
+
+ .sidebar-content
+ padding: 12px
+ margin-bottom: 1.6em
position: absolute
top: 0
bottom: 0
@@ -73,6 +81,16 @@
i.fa
margin-right: 10px
+ .sidebar-shortcuts
+ margin: 0
+ padding: 0
+ top: auto
+ text-align: center
+ font-size: 0.8em
+ line-height: 1.6em
+ vertical-align: middle
+ color: darken(white, 40%)
+
.board-sidebar
width: 248px
right: -@width
diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade
index ad41e8aa..51b0888b 100644
--- a/client/components/users/userHeader.jade
+++ b/client/components/users/userHeader.jade
@@ -17,6 +17,8 @@ template(name="memberMenuPopup")
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
+ if currentUser.isAdmin
+ li: a.js-go-setting(href='/setting') {{_ 'admin-panel'}}
hr
ul.pop-over-list
li: a.js-logout {{_ 'log-out'}}
diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js
index 98053ed1..73a11fc0 100644
--- a/client/components/users/userHeader.js
+++ b/client/components/users/userHeader.js
@@ -15,6 +15,9 @@ Template.memberMenuPopup.events({
AccountsTemplates.logout();
},
+ 'click .js-go-setting'() {
+ Popup.close();
+ },
});
Template.editProfilePopup.events({