mirror of
https://github.com/wekan/wekan.git
synced 2025-12-17 16:00:13 +01:00
My Cards and Due Cards development
* add spinner while pages are loading * use a single publication for My Cards * add Due Cards to the user menu * add description to the All Users option for Due Cards * some code clean-up
This commit is contained in:
parent
55b121e0d3
commit
ecc3558987
10 changed files with 197 additions and 185 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
template(name="dueCardsHeaderBar")
|
template(name="dueCardsHeaderBar")
|
||||||
h1
|
h1
|
||||||
//a.back-btn(href="{{pathFor 'home'}}")
|
i.fa.fa-calendar
|
||||||
// i.fa.fa-chevron-left
|
|
||||||
| {{_ 'dueCards-title'}}
|
| {{_ 'dueCards-title'}}
|
||||||
|
|
||||||
.board-header-btns.left
|
.board-header-btns.left
|
||||||
|
|
@ -20,6 +19,7 @@ template(name="dueCardsModalTitle")
|
||||||
| {{_ 'dueCards-title'}}
|
| {{_ 'dueCards-title'}}
|
||||||
|
|
||||||
template(name="dueCards")
|
template(name="dueCards")
|
||||||
|
if isPageReady.get
|
||||||
.wrapper
|
.wrapper
|
||||||
.due-cards-dueat-list-wrapper
|
.due-cards-dueat-list-wrapper
|
||||||
each card in dueCardsList
|
each card in dueCardsList
|
||||||
|
|
@ -44,7 +44,8 @@ template(name="dueCards")
|
||||||
li.due-cards-context(title="{{_ 'list'}}")
|
li.due-cards-context(title="{{_ 'list'}}")
|
||||||
+viewer
|
+viewer
|
||||||
= card.getList.title
|
= card.getList.title
|
||||||
|
else
|
||||||
|
+spinner
|
||||||
|
|
||||||
template(name="dueCardsViewChangePopup")
|
template(name="dueCardsViewChangePopup")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
|
|
@ -60,5 +61,8 @@ template(name="dueCardsViewChangePopup")
|
||||||
a.js-due-cards-view-all
|
a.js-due-cards-view-all
|
||||||
i.fa.fa-users.colorful
|
i.fa.fa-users.colorful
|
||||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||||
|
span.sub-name
|
||||||
|
+viewer
|
||||||
|
| {{_ 'dueCardsViewChange-choice-all-description' }}
|
||||||
if $eq Utils.dueCardsView "all"
|
if $eq Utils.dueCardsView "all"
|
||||||
i.fa.fa-check
|
i.fa.fa-check
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
const subManager = new SubsManager();
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
dueCardsView() {
|
dueCardsView() {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
@ -40,8 +42,20 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
onCreated() {
|
onCreated() {
|
||||||
|
this.isPageReady = new ReactiveVar(false);
|
||||||
|
|
||||||
|
this.autorun(() => {
|
||||||
|
const handle = subManager.subscribe(
|
||||||
|
'dueCards',
|
||||||
|
Utils.dueCardsView() === 'all',
|
||||||
|
);
|
||||||
|
Tracker.nonreactive(() => {
|
||||||
|
Tracker.autorun(() => {
|
||||||
|
this.isPageReady.set(handle.ready());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Meteor.subscribe('setting');
|
Meteor.subscribe('setting');
|
||||||
Meteor.subscribe('dueCards', Utils.dueCardsView() === 'all');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
dueCardsView() {
|
dueCardsView() {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ template(name="myCardsHeaderBar")
|
||||||
h1
|
h1
|
||||||
//a.back-btn(href="{{pathFor 'home'}}")
|
//a.back-btn(href="{{pathFor 'home'}}")
|
||||||
// i.fa.fa-chevron-left
|
// i.fa.fa-chevron-left
|
||||||
|
i.fa.fa-list
|
||||||
| {{_ 'my-cards'}}
|
| {{_ 'my-cards'}}
|
||||||
|
|
||||||
.board-header-btns.left
|
.board-header-btns.left
|
||||||
|
|
@ -20,9 +21,10 @@ template(name="myCardsModalTitle")
|
||||||
| {{_ 'my-cards'}}
|
| {{_ 'my-cards'}}
|
||||||
|
|
||||||
template(name="myCards")
|
template(name="myCards")
|
||||||
|
if isPageReady.get
|
||||||
.wrapper
|
.wrapper
|
||||||
if $eq myCardsSort 'board'
|
if $eq myCardsSort 'board'
|
||||||
each board in myBoards
|
each board in myCardsList
|
||||||
.my-cards-board-wrapper
|
.my-cards-board-wrapper
|
||||||
.my-cards-board-title
|
.my-cards-board-title
|
||||||
+viewer
|
+viewer
|
||||||
|
|
@ -42,7 +44,7 @@ template(name="myCards")
|
||||||
+minicard(card)
|
+minicard(card)
|
||||||
else
|
else
|
||||||
.my-cards-dueat-list-wrapper
|
.my-cards-dueat-list-wrapper
|
||||||
each card in myCardsList
|
each card in myDueCardsList
|
||||||
.my-cards-card-wrapper
|
.my-cards-card-wrapper
|
||||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||||
+minicard(card)
|
+minicard(card)
|
||||||
|
|
@ -64,7 +66,8 @@ template(name="myCards")
|
||||||
li.my-cards-context(title="{{_ 'list'}}")
|
li.my-cards-context(title="{{_ 'list'}}")
|
||||||
+viewer
|
+viewer
|
||||||
= card.getList.title
|
= card.getList.title
|
||||||
|
else
|
||||||
|
+spinner
|
||||||
|
|
||||||
template(name="myCardsSortChangePopup")
|
template(name="myCardsSortChangePopup")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
const subManager = new SubsManager();
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
myCardsSort() {
|
myCardsSort() {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
@ -42,10 +44,17 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
onCreated() {
|
onCreated() {
|
||||||
|
this.isPageReady = new ReactiveVar(false);
|
||||||
|
|
||||||
|
this.autorun(() => {
|
||||||
|
const handle = subManager.subscribe('myCards');
|
||||||
|
Tracker.nonreactive(() => {
|
||||||
|
Tracker.autorun(() => {
|
||||||
|
this.isPageReady.set(handle.ready());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Meteor.subscribe('setting');
|
Meteor.subscribe('setting');
|
||||||
Meteor.subscribe('myCards');
|
|
||||||
Meteor.subscribe('mySwimlanes');
|
|
||||||
Meteor.subscribe('myLists');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
myCardsSort() {
|
myCardsSort() {
|
||||||
|
|
@ -58,7 +67,7 @@ BlazeComponent.extendComponent({
|
||||||
return this.myCardsSort() === 'board';
|
return this.myCardsSort() === 'board';
|
||||||
},
|
},
|
||||||
|
|
||||||
myBoards() {
|
myCardsList() {
|
||||||
const userId = Meteor.userId();
|
const userId = Meteor.userId();
|
||||||
const boards = [];
|
const boards = [];
|
||||||
let board = null;
|
let board = null;
|
||||||
|
|
@ -173,7 +182,7 @@ BlazeComponent.extendComponent({
|
||||||
return boards;
|
return boards;
|
||||||
},
|
},
|
||||||
|
|
||||||
myCardsList() {
|
myDueCardsList() {
|
||||||
const userId = Meteor.userId();
|
const userId = Meteor.userId();
|
||||||
|
|
||||||
const cursor = Cards.find(
|
const cursor = Cards.find(
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ template(name="memberMenuPopup")
|
||||||
a.js-my-cards(href="{{pathFor 'my-cards'}}")
|
a.js-my-cards(href="{{pathFor 'my-cards'}}")
|
||||||
i.fa.fa-list
|
i.fa.fa-list
|
||||||
| {{_ 'my-cards'}}
|
| {{_ 'my-cards'}}
|
||||||
|
li
|
||||||
|
a.js-due-cards(href="{{pathFor 'due-cards'}}")
|
||||||
|
i.fa.fa-calendar
|
||||||
|
| {{_ 'dueCards-title'}}
|
||||||
li
|
li
|
||||||
a(href="{{pathFor 'home'}}")
|
a(href="{{pathFor 'home'}}")
|
||||||
span.fa.fa-home
|
span.fa.fa-home
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ Template.memberMenuPopup.events({
|
||||||
'click .js-my-cards'() {
|
'click .js-my-cards'() {
|
||||||
Popup.close();
|
Popup.close();
|
||||||
},
|
},
|
||||||
|
'click .js-due-cards'() {
|
||||||
|
Popup.close();
|
||||||
|
},
|
||||||
'click .js-open-archived-board'() {
|
'click .js-open-archived-board'() {
|
||||||
Modal.open('archivedBoards');
|
Modal.open('archivedBoards');
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,6 @@ FlowRouter.route('/shortcuts', {
|
||||||
FlowRouter.route('/my-cards', {
|
FlowRouter.route('/my-cards', {
|
||||||
name: 'my-cards',
|
name: 'my-cards',
|
||||||
action() {
|
action() {
|
||||||
const myCardsTemplate = 'myCards';
|
|
||||||
|
|
||||||
Filter.reset();
|
Filter.reset();
|
||||||
// EscapeActions.executeAll();
|
// EscapeActions.executeAll();
|
||||||
EscapeActions.executeUpTo('popup-close');
|
EscapeActions.executeUpTo('popup-close');
|
||||||
|
|
@ -125,15 +123,9 @@ FlowRouter.route('/my-cards', {
|
||||||
Utils.manageCustomUI();
|
Utils.manageCustomUI();
|
||||||
Utils.manageMatomo();
|
Utils.manageMatomo();
|
||||||
|
|
||||||
// if (previousPath) {
|
|
||||||
// Modal.open(myCardsTemplate, {
|
|
||||||
// header: 'myCardsModalTitle',
|
|
||||||
// onCloseGoTo: previousPath,
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
BlazeLayout.render('defaultLayout', {
|
BlazeLayout.render('defaultLayout', {
|
||||||
headerBar: 'myCardsHeaderBar',
|
headerBar: 'myCardsHeaderBar',
|
||||||
content: myCardsTemplate,
|
content: 'myCards',
|
||||||
});
|
});
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
|
|
@ -142,8 +134,6 @@ FlowRouter.route('/my-cards', {
|
||||||
FlowRouter.route('/due-cards', {
|
FlowRouter.route('/due-cards', {
|
||||||
name: 'due-cards',
|
name: 'due-cards',
|
||||||
action() {
|
action() {
|
||||||
const dueCardsTemplate = 'dueCards';
|
|
||||||
|
|
||||||
Filter.reset();
|
Filter.reset();
|
||||||
// EscapeActions.executeAll();
|
// EscapeActions.executeAll();
|
||||||
EscapeActions.executeUpTo('popup-close');
|
EscapeActions.executeUpTo('popup-close');
|
||||||
|
|
@ -151,15 +141,9 @@ FlowRouter.route('/due-cards', {
|
||||||
Utils.manageCustomUI();
|
Utils.manageCustomUI();
|
||||||
Utils.manageMatomo();
|
Utils.manageMatomo();
|
||||||
|
|
||||||
// if (previousPath) {
|
|
||||||
// Modal.open(dueCardsTemplate, {
|
|
||||||
// header: 'dueCardsModalTitle',
|
|
||||||
// onCloseGoTo: previousPath,
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
BlazeLayout.render('defaultLayout', {
|
BlazeLayout.render('defaultLayout', {
|
||||||
headerBar: 'dueCardsHeaderBar',
|
headerBar: 'dueCardsHeaderBar',
|
||||||
content: dueCardsTemplate,
|
content: 'dueCards',
|
||||||
});
|
});
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -860,5 +860,6 @@
|
||||||
"dueCards-title": "Due Cards",
|
"dueCards-title": "Due Cards",
|
||||||
"dueCardsViewChange-title": "Due Cards View",
|
"dueCardsViewChange-title": "Due Cards View",
|
||||||
"dueCardsViewChange-choice-me": "Me",
|
"dueCardsViewChange-choice-me": "Me",
|
||||||
"dueCardsViewChange-choice-all": "All Users"
|
"dueCardsViewChange-choice-all": "All Users",
|
||||||
|
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,71 +43,6 @@ Meteor.publish('boards', function() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Meteor.publish('mySwimlanes', function() {
|
|
||||||
const userId = this.userId;
|
|
||||||
const swimlanes = [];
|
|
||||||
|
|
||||||
Cards.find({
|
|
||||||
archived: false,
|
|
||||||
$or: [{ members: userId }, { assignees: userId }],
|
|
||||||
}).forEach(card => {
|
|
||||||
swimlanes.push(card.swimlaneId);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Swimlanes.find(
|
|
||||||
{
|
|
||||||
// archived: false,
|
|
||||||
_id: { $in: swimlanes },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: {
|
|
||||||
_id: 1,
|
|
||||||
title: 1,
|
|
||||||
boardId: 1,
|
|
||||||
type: 1,
|
|
||||||
color: 1,
|
|
||||||
sort: 1,
|
|
||||||
},
|
|
||||||
// sort: {
|
|
||||||
// sort: ['boardId', 'listId', 'sort'],
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Meteor.publish('myLists', function() {
|
|
||||||
const userId = this.userId;
|
|
||||||
const lists = [];
|
|
||||||
|
|
||||||
Cards.find({
|
|
||||||
archived: false,
|
|
||||||
$or: [{ members: userId }, { assignees: userId }],
|
|
||||||
}).forEach(card => {
|
|
||||||
lists.push(card.listId);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Lists.find(
|
|
||||||
{
|
|
||||||
// archived: false,
|
|
||||||
_id: { $in: lists },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: {
|
|
||||||
_id: 1,
|
|
||||||
boardId: 1,
|
|
||||||
swimlaneId: 1,
|
|
||||||
title: 1,
|
|
||||||
color: 1,
|
|
||||||
type: 1,
|
|
||||||
sort: 1,
|
|
||||||
},
|
|
||||||
// sort: {
|
|
||||||
// sort: ['boardId', 'listId', 'sort'],
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Meteor.publish('archivedBoards', function() {
|
Meteor.publish('archivedBoards', function() {
|
||||||
const userId = this.userId;
|
const userId = this.userId;
|
||||||
if (!Match.test(userId, String)) return [];
|
if (!Match.test(userId, String)) return [];
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,32 @@ Meteor.publish('card', cardId => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Meteor.publish('myCards', function() {
|
Meteor.publish('myCards', function() {
|
||||||
const userId = this.userId;
|
const userId = Meteor.userId();
|
||||||
|
|
||||||
return Cards.find(
|
const archivedBoards = [];
|
||||||
{
|
Boards.find({ archived: true }).forEach(board => {
|
||||||
|
archivedBoards.push(board._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const archivedSwimlanes = [];
|
||||||
|
Swimlanes.find({ archived: true }).forEach(swimlane => {
|
||||||
|
archivedSwimlanes.push(swimlane._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const archivedLists = [];
|
||||||
|
Lists.find({ archived: true }).forEach(list => {
|
||||||
|
archivedLists.push(list._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
selector = {
|
||||||
archived: false,
|
archived: false,
|
||||||
|
boardId: { $nin: archivedBoards },
|
||||||
|
swimlaneId: { $nin: archivedSwimlanes },
|
||||||
|
listId: { $nin: archivedLists },
|
||||||
$or: [{ members: userId }, { assignees: userId }],
|
$or: [{ members: userId }, { assignees: userId }],
|
||||||
},
|
};
|
||||||
{
|
|
||||||
|
const cards = Cards.find(selector, {
|
||||||
fields: {
|
fields: {
|
||||||
_id: 1,
|
_id: 1,
|
||||||
archived: 1,
|
archived: 1,
|
||||||
|
|
@ -26,11 +44,36 @@ Meteor.publish('myCards', function() {
|
||||||
colors: 1,
|
colors: 1,
|
||||||
dueAt: 1,
|
dueAt: 1,
|
||||||
},
|
},
|
||||||
// sort: {
|
});
|
||||||
// sort: ['boardId', 'listId', 'sort'],
|
|
||||||
// },
|
const boards = [];
|
||||||
},
|
const swimlanes = [];
|
||||||
);
|
const lists = [];
|
||||||
|
const users = [];
|
||||||
|
|
||||||
|
cards.forEach(card => {
|
||||||
|
if (card.boardId) boards.push(card.boardId);
|
||||||
|
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
||||||
|
if (card.listId) lists.push(card.listId);
|
||||||
|
if (card.members) {
|
||||||
|
card.members.forEach(userId => {
|
||||||
|
users.push(userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (card.assignees) {
|
||||||
|
card.assignees.forEach(userId => {
|
||||||
|
users.push(userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
cards,
|
||||||
|
Boards.find({ _id: { $in: boards } }),
|
||||||
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||||
|
Lists.find({ _id: { $in: lists } }),
|
||||||
|
Users.find({ _id: { $in: users } }),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
Meteor.publish('dueCards', function(allUsers = false) {
|
Meteor.publish('dueCards', function(allUsers = false) {
|
||||||
|
|
@ -105,11 +148,22 @@ Meteor.publish('dueCards', function(allUsers = false) {
|
||||||
const boards = [];
|
const boards = [];
|
||||||
const swimlanes = [];
|
const swimlanes = [];
|
||||||
const lists = [];
|
const lists = [];
|
||||||
|
const users = [];
|
||||||
|
|
||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
if (card.boardId) boards.push(card.boardId);
|
if (card.boardId) boards.push(card.boardId);
|
||||||
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
||||||
if (card.listId) lists.push(card.listId);
|
if (card.listId) lists.push(card.listId);
|
||||||
|
if (card.members) {
|
||||||
|
card.members.forEach(userId => {
|
||||||
|
users.push(userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (card.assignees) {
|
||||||
|
card.assignees.forEach(userId => {
|
||||||
|
users.push(userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -117,5 +171,6 @@ Meteor.publish('dueCards', function(allUsers = false) {
|
||||||
Boards.find({ _id: { $in: boards } }),
|
Boards.find({ _id: { $in: boards } }),
|
||||||
Swimlanes.find({ _id: { $in: swimlanes } }),
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||||
Lists.find({ _id: { $in: lists } }),
|
Lists.find({ _id: { $in: lists } }),
|
||||||
|
Users.find({ _id: { $in: users } }),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue