mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 23:40:13 +01:00
Initial work on due cards page
This commit is contained in:
parent
108d01ee35
commit
1abdd5177d
7 changed files with 483 additions and 1 deletions
76
client/components/main/dueCards.jade
Normal file
76
client/components/main/dueCards.jade
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
template(name="dueCardsHeaderBar")
|
||||||
|
h1
|
||||||
|
//a.back-btn(href="{{pathFor 'home'}}")
|
||||||
|
// i.fa.fa-chevron-left
|
||||||
|
| {{_ 'due-cards'}}
|
||||||
|
|
||||||
|
.board-header-btns.left
|
||||||
|
a.board-header-btn.js-toggle-due-cards-choose-sort(title="{{_ 'due-cards-sort'}}")
|
||||||
|
//i.fa.fa-caret-down
|
||||||
|
i.fa.fa-sort
|
||||||
|
if $eq dueCardsView 'user'
|
||||||
|
i.fa.fa-th-large
|
||||||
|
| {{_ 'due-cards-sort-board'}}
|
||||||
|
if $eq dueCardsView 'all'
|
||||||
|
i.fa.fa-calendar
|
||||||
|
| {{_ 'due-cards-sort-dueat'}}
|
||||||
|
|
||||||
|
template(name="dueCardsModalTitle")
|
||||||
|
h2
|
||||||
|
i.fa.fa-keyboard-o
|
||||||
|
| {{_ 'due-cards'}}
|
||||||
|
|
||||||
|
template(name="dueCards")
|
||||||
|
.wrapper
|
||||||
|
.due-cards-dueat-list-wrapper
|
||||||
|
each card in dueCardsList
|
||||||
|
.due-cards-card-wrapper
|
||||||
|
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||||
|
+minicard(card)
|
||||||
|
ul.due-cards-context-list
|
||||||
|
li.due-cards-context(title="{{_ 'board'}}")
|
||||||
|
+viewer
|
||||||
|
= card.board.title
|
||||||
|
li.due-cards-context.due-cards-context-separator
|
||||||
|
= ' '
|
||||||
|
| {{_ 'context-separator'}}
|
||||||
|
= ' '
|
||||||
|
li.due-cards-context(title="{{_ 'swimlane'}}")
|
||||||
|
+viewer
|
||||||
|
= card.swimlane.title
|
||||||
|
li.due-cards-context
|
||||||
|
= ' '
|
||||||
|
| {{_ 'context-separator'}}
|
||||||
|
= ' '
|
||||||
|
li.due-cards-context(title="{{_ 'list'}}")
|
||||||
|
+viewer
|
||||||
|
= card.list.title
|
||||||
|
|
||||||
|
|
||||||
|
template(name="dueCardsViewChangePopup")
|
||||||
|
ul.pop-over-list
|
||||||
|
li
|
||||||
|
with "due-cards-view-user"
|
||||||
|
a.js-due-cards-sort-board
|
||||||
|
i.fa.fa-th-large.colorful
|
||||||
|
| {{_ 'due-cards-view-user'}}
|
||||||
|
if $eq Utils.dueCardsView "user"
|
||||||
|
i.fa.fa-check
|
||||||
|
li
|
||||||
|
with "due-cards-view-all"
|
||||||
|
a.js-due-cards-sort-dueat
|
||||||
|
i.fa.fa-calendar.colorful
|
||||||
|
| {{_ 'due-cards-view-all'}}
|
||||||
|
if $eq Utils.dueCardsView "all"
|
||||||
|
i.fa.fa-check
|
||||||
|
|
||||||
|
//template(name="dueCardsViewChangePopup")
|
||||||
|
// ul.pop-over-list
|
||||||
|
// li
|
||||||
|
// a.js-due-cards-sort-board
|
||||||
|
// i.fa.fa-th-large.colorful
|
||||||
|
// | {{_ 'due-cards-sort-board'}}
|
||||||
|
// li
|
||||||
|
// a.js-due-cards-sort-dueat
|
||||||
|
// i.fa.fa-calendar.colorful
|
||||||
|
// | {{_ 'due-cards-sort-dueat'}}
|
||||||
163
client/components/main/dueCards.js
Normal file
163
client/components/main/dueCards.js
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
dueCardsView() {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log('sort:', Utils.dueCardsView());
|
||||||
|
return Utils.dueCardsView();
|
||||||
|
},
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'click .js-toggle-my-cards-choose-sort'() {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log('open sort');
|
||||||
|
// Popup.open('dueCardsViewChange');
|
||||||
|
Utils.dueCardsViewToggle();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}).register('dueCardsHeaderBar');
|
||||||
|
|
||||||
|
Template.dueCards.helpers({
|
||||||
|
userId() {
|
||||||
|
return Meteor.userId();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
events() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'click .js-my-cards-sort-board'() {
|
||||||
|
Utils.setMyCardsSort('board');
|
||||||
|
Popup.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
'click .js-my-cards-sort-dueat'() {
|
||||||
|
Utils.setMyCardsSort('dueAt');
|
||||||
|
Popup.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}).register('dueCardsViewChangePopup');
|
||||||
|
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
onCreated() {
|
||||||
|
Meteor.subscribe('setting');
|
||||||
|
Meteor.subscribe('dueCards');
|
||||||
|
},
|
||||||
|
|
||||||
|
dueCardsView() {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('sort:', Utils.dueCardsView());
|
||||||
|
return Utils.dueCardsView();
|
||||||
|
},
|
||||||
|
|
||||||
|
sortByBoard() {
|
||||||
|
return this.dueCardsView() === 'board';
|
||||||
|
},
|
||||||
|
|
||||||
|
dueCardsList() {
|
||||||
|
const allUsers = false;
|
||||||
|
|
||||||
|
const user = Meteor.user();
|
||||||
|
|
||||||
|
const archivedBoards = [];
|
||||||
|
Boards.find({ archived: true }).forEach(board => {
|
||||||
|
archivedBoards.push(board._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const permiitedBoards = [];
|
||||||
|
let selector = {
|
||||||
|
archived: false,
|
||||||
|
};
|
||||||
|
// if user is not an admin allow her to see cards only from public boards
|
||||||
|
// or those where she is a member
|
||||||
|
if (!user.isAdmin) {
|
||||||
|
selector.$or = [
|
||||||
|
{ permission: 'public' },
|
||||||
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
Boards.find(selector).forEach(board => {
|
||||||
|
permiitedBoards.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,
|
||||||
|
boardId: {
|
||||||
|
$nin: archivedBoards,
|
||||||
|
$in: permiitedBoards,
|
||||||
|
},
|
||||||
|
swimlaneId: { $nin: archivedSwimlanes },
|
||||||
|
listId: { $nin: archivedLists },
|
||||||
|
dueAt: { $ne: null },
|
||||||
|
endAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!allUsers) {
|
||||||
|
selector.$or = [{ members: user._id }, { assignees: user._id }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cards = [];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log('cards selector:', selector);
|
||||||
|
Cards.find(selector).forEach(card => {
|
||||||
|
cards.push(card);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log(
|
||||||
|
// 'board:',
|
||||||
|
// card.board(),
|
||||||
|
// 'swimlane:',
|
||||||
|
// card.swimlane(),
|
||||||
|
// 'list:',
|
||||||
|
// card.list(),
|
||||||
|
// );
|
||||||
|
});
|
||||||
|
|
||||||
|
cards.sort((a, b) => {
|
||||||
|
const x = a.dueAt === null ? Date('2100-12-31') : a.dueAt;
|
||||||
|
const y = b.dueAt === null ? Date('2100-12-31') : b.dueAt;
|
||||||
|
|
||||||
|
if (x > y) return 1;
|
||||||
|
else if (x < y) return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log('cards:', cards);
|
||||||
|
return cards;
|
||||||
|
},
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
// 'click .js-my-card'(evt) {
|
||||||
|
// const card = this.currentData().card;
|
||||||
|
// // eslint-disable-next-line no-console
|
||||||
|
// console.log('currentData():', this.currentData());
|
||||||
|
// // eslint-disable-next-line no-console
|
||||||
|
// console.log('card:', card);
|
||||||
|
// if (card) {
|
||||||
|
// Utils.goCardId(card._id);
|
||||||
|
// }
|
||||||
|
// evt.preventDefault();
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}).register('dueCards');
|
||||||
69
client/components/main/dueCards.styl
Normal file
69
client/components/main/dueCards.styl
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
.due-cards-board-wrapper
|
||||||
|
border-radius: 8px
|
||||||
|
//padding: 0.5rem
|
||||||
|
min-width: 400px
|
||||||
|
border-width: 8px
|
||||||
|
border-color: grey
|
||||||
|
border-style: solid
|
||||||
|
margin-bottom: 2rem
|
||||||
|
margin-right: auto
|
||||||
|
margin-left: auto
|
||||||
|
|
||||||
|
.due-cards-board-title
|
||||||
|
font-size: 1.4rem
|
||||||
|
font-weight: bold
|
||||||
|
padding: 0.5rem
|
||||||
|
background-color: grey
|
||||||
|
color: white
|
||||||
|
|
||||||
|
.due-cards-swimlane-title
|
||||||
|
font-size: 1.1rem
|
||||||
|
font-weight: bold
|
||||||
|
padding: 0.5rem
|
||||||
|
padding-bottom: 0.4rem
|
||||||
|
margin-top: 0
|
||||||
|
margin-bottom: 0.5rem
|
||||||
|
//border-top: black 1px solid
|
||||||
|
//border-bottom: black 1px solid
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.swimlane-default-color
|
||||||
|
background-color: lightgrey
|
||||||
|
|
||||||
|
.due-cards-list-title
|
||||||
|
font-weight: bold
|
||||||
|
font-size: 1.1rem
|
||||||
|
//padding-bottom: 0
|
||||||
|
//margin-bottom: 0
|
||||||
|
text-align: center
|
||||||
|
margin-bottom: 0.7rem
|
||||||
|
|
||||||
|
.due-cards-list-wrapper
|
||||||
|
margin: 1rem
|
||||||
|
border-radius: 5px
|
||||||
|
padding: 1.5rem
|
||||||
|
padding-top: 0.75rem
|
||||||
|
display: inline-block
|
||||||
|
min-width: 250px
|
||||||
|
max-width: 350px
|
||||||
|
|
||||||
|
.due-cards-card-wrapper
|
||||||
|
margin-top: 0
|
||||||
|
margin-bottom: 10px
|
||||||
|
|
||||||
|
.due-cards-dueat-list-wrapper
|
||||||
|
max-width: 500px
|
||||||
|
margin-right: auto
|
||||||
|
margin-left: auto
|
||||||
|
|
||||||
|
.due-cards-field-name
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
.due-cards-context
|
||||||
|
display: inline-block
|
||||||
|
|
||||||
|
.due-cards-context-separator
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
.due-cards-context-list
|
||||||
|
margin-bottom: 0.7rem
|
||||||
|
|
@ -200,7 +200,13 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
const cards = [];
|
const cards = [];
|
||||||
cursor.forEach(card => {
|
cursor.forEach(card => {
|
||||||
cards.push(card);
|
if (
|
||||||
|
!card.board().archived &&
|
||||||
|
!card.swimlane().archived &&
|
||||||
|
!card.list().archived
|
||||||
|
) {
|
||||||
|
cards.push(card);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cards.sort((a, b) => {
|
cards.sort((a, b) => {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,64 @@ Utils = {
|
||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
archivedBoardIds() {
|
||||||
|
const archivedBoards = [];
|
||||||
|
Boards.find({ archived: false }).forEach(board => {
|
||||||
|
archivedBoards.push(board._id);
|
||||||
|
});
|
||||||
|
return archivedBoards;
|
||||||
|
},
|
||||||
|
|
||||||
|
dueCardsView() {
|
||||||
|
let view = window.localStorage.getItem('dueCardsView');
|
||||||
|
|
||||||
|
if (!view || !['user', 'all'].includes(view)) {
|
||||||
|
window.localStorage.setItem('dueCardsView', 'user');
|
||||||
|
location.reload();
|
||||||
|
view = 'user';
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
},
|
||||||
|
|
||||||
|
dueBoardsSelector() {
|
||||||
|
const user = Meteor.user();
|
||||||
|
|
||||||
|
const selector = {
|
||||||
|
archived: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// if user is not an admin allow her to see cards only from boards where
|
||||||
|
// she is a member
|
||||||
|
if (!user.isAdmin()) {
|
||||||
|
selector.$or = [
|
||||||
|
{ permission: 'public' },
|
||||||
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return selector;
|
||||||
|
},
|
||||||
|
|
||||||
|
dueCardsSelector() {
|
||||||
|
const user = Meteor.user();
|
||||||
|
|
||||||
|
const selector = {
|
||||||
|
archived: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// if user is not an admin allow her to see cards only from boards where
|
||||||
|
// she is a member
|
||||||
|
if (!user.isAdmin()) {
|
||||||
|
selector.$or = [
|
||||||
|
{ permission: 'public' },
|
||||||
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return selector;
|
||||||
|
},
|
||||||
|
|
||||||
// XXX We should remove these two methods
|
// XXX We should remove these two methods
|
||||||
goBoardId(_id) {
|
goBoardId(_id) {
|
||||||
const board = Boards.findOne(_id);
|
const board = Boards.findOne(_id);
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,32 @@ FlowRouter.route('/my-cards', {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
FlowRouter.route('/due-cards', {
|
||||||
|
name: 'my-cards',
|
||||||
|
action() {
|
||||||
|
const dueCardsTemplate = 'dueCards';
|
||||||
|
|
||||||
|
Filter.reset();
|
||||||
|
// EscapeActions.executeAll();
|
||||||
|
EscapeActions.executeUpTo('popup-close');
|
||||||
|
|
||||||
|
Utils.manageCustomUI();
|
||||||
|
Utils.manageMatomo();
|
||||||
|
|
||||||
|
// if (previousPath) {
|
||||||
|
// Modal.open(dueCardsTemplate, {
|
||||||
|
// header: 'dueCardsModalTitle',
|
||||||
|
// onCloseGoTo: previousPath,
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
BlazeLayout.render('defaultLayout', {
|
||||||
|
headerBar: 'dueCardsHeaderBar',
|
||||||
|
content: dueCardsTemplate,
|
||||||
|
});
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
FlowRouter.route('/import/:source', {
|
FlowRouter.route('/import/:source', {
|
||||||
name: 'import',
|
name: 'import',
|
||||||
triggersEnter: [AccountsTemplates.ensureSignedIn],
|
triggersEnter: [AccountsTemplates.ensureSignedIn],
|
||||||
|
|
|
||||||
|
|
@ -32,3 +32,87 @@ Meteor.publish('myCards', function() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Meteor.publish('dueCards', function(allUsers = false) {
|
||||||
|
check(allUsers, Boolean);
|
||||||
|
|
||||||
|
const user = Users.findOne(this.userId);
|
||||||
|
|
||||||
|
const archivedBoards = [];
|
||||||
|
Boards.find({ archived: true }).forEach(board => {
|
||||||
|
archivedBoards.push(board._id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const permiitedBoards = [];
|
||||||
|
let selector = {
|
||||||
|
archived: false,
|
||||||
|
};
|
||||||
|
// if user is not an admin allow her to see cards only from boards where
|
||||||
|
// she is a member
|
||||||
|
if (!user.isAdmin) {
|
||||||
|
selector.$or = [
|
||||||
|
{ permission: 'public' },
|
||||||
|
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
Boards.find(selector).forEach(board => {
|
||||||
|
permiitedBoards.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,
|
||||||
|
boardId: { $nin: archivedBoards, $in: permiitedBoards },
|
||||||
|
swimlaneId: { $nin: archivedSwimlanes },
|
||||||
|
listId: { $nin: archivedLists },
|
||||||
|
dueAt: { $ne: null },
|
||||||
|
endAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!allUsers) {
|
||||||
|
selector.$or = [{ members: user._id }, { assignees: user._id }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cards = Cards.find(selector, {
|
||||||
|
fields: {
|
||||||
|
_id: 1,
|
||||||
|
archived: 1,
|
||||||
|
boardId: 1,
|
||||||
|
swimlaneId: 1,
|
||||||
|
listId: 1,
|
||||||
|
title: 1,
|
||||||
|
type: 1,
|
||||||
|
sort: 1,
|
||||||
|
members: 1,
|
||||||
|
assignees: 1,
|
||||||
|
colors: 1,
|
||||||
|
dueAt: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const boards = [];
|
||||||
|
const swimlanes = [];
|
||||||
|
const lists = [];
|
||||||
|
|
||||||
|
cards.forEach(card => {
|
||||||
|
boards.push(card.boardId);
|
||||||
|
swimlanes.push(card.swimlaneId);
|
||||||
|
lists.push(card.listId);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
cards,
|
||||||
|
Boards.find({ _id: { $in: boards } }),
|
||||||
|
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||||
|
Lists.find({ _id: { $in: lists } }),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue