Fixed #2338 -> Slow opening of big boards with too many archived items

This commit is contained in:
wekan 2019-05-13 11:01:50 +02:00
parent b983479476
commit ab4fec0f3c
8 changed files with 92 additions and 64 deletions

View file

@ -14,7 +14,7 @@ BlazeComponent.extendComponent({
const currentBoardId = Session.get('currentBoard'); const currentBoardId = Session.get('currentBoard');
if (!currentBoardId) if (!currentBoardId)
return; return;
const handle = subManager.subscribe('board', currentBoardId); const handle = subManager.subscribe('board', currentBoardId, false);
Tracker.nonreactive(() => { Tracker.nonreactive(() => {
Tracker.autorun(() => { Tracker.autorun(() => {
this.isBoardReady.set(handle.ready()); this.isBoardReady.set(handle.ready());

View file

@ -33,12 +33,12 @@ BlazeComponent.extendComponent({
}, },
hasOvertimeCards() { hasOvertimeCards() {
subManager.subscribe('board', this.currentData()._id); subManager.subscribe('board', this.currentData()._id, false);
return this.currentData().hasOvertimeCards(); return this.currentData().hasOvertimeCards();
}, },
hasSpentTimeCards() { hasSpentTimeCards() {
subManager.subscribe('board', this.currentData()._id); subManager.subscribe('board', this.currentData()._id, false);
return this.currentData().hasSpentTimeCards(); return this.currentData().hasSpentTimeCards();
}, },

View file

@ -424,7 +424,7 @@ Template.moveCardPopup.events({
}); });
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
onCreated() { onCreated() {
subManager.subscribe('board', Session.get('currentBoard')); subManager.subscribe('board', Session.get('currentBoard'), false);
this.selectedBoardId = new ReactiveVar(Session.get('currentBoard')); this.selectedBoardId = new ReactiveVar(Session.get('currentBoard'));
}, },
@ -453,7 +453,7 @@ BlazeComponent.extendComponent({
return [{ return [{
'change .js-select-boards'(evt) { 'change .js-select-boards'(evt) {
this.selectedBoardId.set($(evt.currentTarget).val()); this.selectedBoardId.set($(evt.currentTarget).val());
subManager.subscribe('board', this.selectedBoardId.get()); subManager.subscribe('board', this.selectedBoardId.get(), false);
}, },
}]; }];
}, },
@ -676,7 +676,7 @@ BlazeComponent.extendComponent({
if (selection === 'none') { if (selection === 'none') {
this.parentBoard.set(null); this.parentBoard.set(null);
} else { } else {
subManager.subscribe('board', $(evt.currentTarget).val()); subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.parentBoard.set(selection); this.parentBoard.set(selection);
list.prop('disabled', false); list.prop('disabled', false);
} }

View file

@ -348,7 +348,7 @@ BlazeComponent.extendComponent({
this.boardId = Session.get('currentBoard'); this.boardId = Session.get('currentBoard');
// In order to get current board info // In order to get current board info
subManager.subscribe('board', this.boardId); subManager.subscribe('board', this.boardId, false);
this.board = Boards.findOne(this.boardId); this.board = Boards.findOne(this.boardId);
// List where to insert card // List where to insert card
const list = $(Popup._getTopStack().openerElement).closest('.js-list'); const list = $(Popup._getTopStack().openerElement).closest('.js-list');
@ -414,7 +414,7 @@ BlazeComponent.extendComponent({
events() { events() {
return [{ return [{
'change .js-select-boards'(evt) { 'change .js-select-boards'(evt) {
subManager.subscribe('board', $(evt.currentTarget).val()); subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.selectedBoardId.set($(evt.currentTarget).val()); this.selectedBoardId.set($(evt.currentTarget).val());
}, },
'change .js-select-swimlanes'(evt) { 'change .js-select-swimlanes'(evt) {
@ -500,13 +500,13 @@ BlazeComponent.extendComponent({
} }
const boardId = board._id; const boardId = board._id;
// Subscribe to this board // Subscribe to this board
subManager.subscribe('board', boardId); subManager.subscribe('board', boardId, false);
this.selectedBoardId = new ReactiveVar(boardId); this.selectedBoardId = new ReactiveVar(boardId);
if (!this.isBoardTemplateSearch) { if (!this.isBoardTemplateSearch) {
this.boardId = Session.get('currentBoard'); this.boardId = Session.get('currentBoard');
// In order to get current board info // In order to get current board info
subManager.subscribe('board', this.boardId); subManager.subscribe('board', this.boardId, false);
this.swimlaneId = ''; this.swimlaneId = '';
// Swimlane where to insert card // Swimlane where to insert card
const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane'); const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
@ -547,7 +547,7 @@ BlazeComponent.extendComponent({
} else if (this.isBoardTemplateSearch) { } else if (this.isBoardTemplateSearch) {
const boards = board.searchBoards(this.term.get()); const boards = board.searchBoards(this.term.get());
boards.forEach((board) => { boards.forEach((board) => {
subManager.subscribe('board', board.linkedId); subManager.subscribe('board', board.linkedId, false);
}); });
return boards; return boards;
} else { } else {
@ -558,7 +558,7 @@ BlazeComponent.extendComponent({
events() { events() {
return [{ return [{
'change .js-select-boards'(evt) { 'change .js-select-boards'(evt) {
subManager.subscribe('board', $(evt.currentTarget).val()); subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.selectedBoardId.set($(evt.currentTarget).val()); this.selectedBoardId.set($(evt.currentTarget).val());
}, },
'submit .js-search-term-form'(evt) { 'submit .js-search-term-form'(evt) {

View file

@ -1,54 +1,56 @@
template(name="archivesSidebar") template(name="archivesSidebar")
+basicTabs(tabs=tabs) if isArchiveReady.get
+basicTabs(tabs=tabs)
+tabContent(slug="cards") +tabContent(slug="cards")
p.quiet
a.js-restore-all-cards {{_ 'restore-all'}}
| -
a.js-delete-all-cards {{_ 'delete-all'}}
each archivedCards
.minicard-wrapper.js-minicard
+minicard(this)
if currentUser.isBoardMember
p.quiet p.quiet
a.js-restore-card {{_ 'restore'}} a.js-restore-all-cards {{_ 'restore-all'}}
| - | -
a.js-delete-card {{_ 'delete'}} a.js-delete-all-cards {{_ 'delete-all'}}
if cardIsInArchivedList each archivedCards
p.quiet.small ({{_ 'warn-list-archived'}}) .minicard-wrapper.js-minicard
else +minicard(this)
p.no-items-message {{_ 'no-archived-cards'}}
+tabContent(slug="lists")
p.quiet
a.js-restore-all-lists {{_ 'restore-all'}}
| -
a.js-delete-all-lists {{_ 'delete-all'}}
ul.archived-lists
each archivedLists
li.archived-lists-item
= title
if currentUser.isBoardMember if currentUser.isBoardMember
p.quiet p.quiet
a.js-restore-list {{_ 'restore'}} a.js-restore-card {{_ 'restore'}}
| - | -
a.js-delete-list {{_ 'delete'}} a.js-delete-card {{_ 'delete'}}
else if cardIsInArchivedList
li.no-items-message {{_ 'no-archived-lists'}} p.quiet.small ({{_ 'warn-list-archived'}})
else
p.no-items-message {{_ 'no-archived-cards'}}
+tabContent(slug="swimlanes") +tabContent(slug="lists")
p.quiet p.quiet
a.js-restore-all-swimlanes {{_ 'restore-all'}} a.js-restore-all-lists {{_ 'restore-all'}}
| - | -
a.js-delete-all-swimlanes {{_ 'delete-all'}} a.js-delete-all-lists {{_ 'delete-all'}}
ul.archived-lists ul.archived-lists
each archivedSwimlanes each archivedLists
li.archived-lists-item li.archived-lists-item
= title = title
if currentUser.isBoardMember if currentUser.isBoardMember
p.quiet p.quiet
a.js-restore-swimlane {{_ 'restore'}} a.js-restore-list {{_ 'restore'}}
| - | -
a.js-delete-swimlane {{_ 'delete'}} a.js-delete-list {{_ 'delete'}}
else else
li.no-items-message {{_ 'no-archived-swimlanes'}} li.no-items-message {{_ 'no-archived-lists'}}
+tabContent(slug="swimlanes")
p.quiet
a.js-restore-all-swimlanes {{_ 'restore-all'}}
| -
a.js-delete-all-swimlanes {{_ 'delete-all'}}
ul.archived-lists
each archivedSwimlanes
li.archived-lists-item
= title
if currentUser.isBoardMember
p.quiet
a.js-restore-swimlane {{_ 'restore'}}
| -
a.js-delete-swimlane {{_ 'delete'}}
else
li.no-items-message {{_ 'no-archived-swimlanes'}}
else
+spinner

View file

@ -1,4 +1,26 @@
const subManager = new SubsManager();
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
onCreated() {
this.isArchiveReady = new ReactiveVar(false);
// The pattern we use to manually handle data loading is described here:
// https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/using-subs-manager
// XXX The boardId should be readed from some sort the component "props",
// unfortunatly, Blaze doesn't have this notion.
this.autorun(() => {
const currentBoardId = Session.get('currentBoard');
if (!currentBoardId)
return;
const handle = subManager.subscribe('board', currentBoardId, true);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
this.isArchiveReady.set( handle.ready() );
});
});
});
},
tabs() { tabs() {
return [ return [
{ name: TAPi18n.__('cards'), slug: 'cards' }, { name: TAPi18n.__('cards'), slug: 'cards' },

View file

@ -59,9 +59,12 @@ Meteor.publish('archivedBoards', function() {
}); });
}); });
Meteor.publishRelations('board', function(boardId) { // If isArchived = false, this will only return board elements which are not archived.
// If isArchived = true, this will only return board elements which are archived.
Meteor.publishRelations('board', function(boardId, isArchived) {
this.unblock(); this.unblock();
check(boardId, String); check(boardId, String);
check(isArchived, Boolean);
const thisUserId = this.userId; const thisUserId = this.userId;
this.cursor(Boards.find({ this.cursor(Boards.find({
@ -75,8 +78,8 @@ Meteor.publishRelations('board', function(boardId) {
], ],
// Sort required to ensure oplog usage // Sort required to ensure oplog usage
}, { limit: 1, sort: { _id: 1 } }), function(boardId, board) { }, { limit: 1, sort: { _id: 1 } }), function(boardId, board) {
this.cursor(Lists.find({ boardId })); this.cursor(Lists.find({ boardId: boardId, archived: isArchived }));
this.cursor(Swimlanes.find({ boardId })); this.cursor(Swimlanes.find({ boardId: boardId, archived: isArchived }));
this.cursor(Integrations.find({ boardId })); this.cursor(Integrations.find({ boardId }));
this.cursor(CustomFields.find({ boardIds: {$in: [boardId]} }, { sort: { name: 1 } })); this.cursor(CustomFields.find({ boardIds: {$in: [boardId]} }, { sort: { name: 1 } }));
@ -115,8 +118,9 @@ Meteor.publishRelations('board', function(boardId) {
parentCards.selector = (_ids) => ({ parentId: _ids }); parentCards.selector = (_ids) => ({ parentId: _ids });
const boards = this.join(Boards); const boards = this.join(Boards);
const subCards = this.join(Cards); const subCards = this.join(Cards);
subCards.selector = (_ids) => ({ archived: isArchived });
this.cursor(Cards.find({ boardId: {$in: [boardId, board.subtasksDefaultBoardId]}}), function(cardId, card) { this.cursor(Cards.find({ boardId: {$in: [boardId, board.subtasksDefaultBoardId]}, archived: isArchived }), function(cardId, card) {
if (card.type === 'cardType-linkedCard') { if (card.type === 'cardType-linkedCard') {
const impCardId = card.linkedId; const impCardId = card.linkedId;
subCards.push(impCardId); subCards.push(impCardId);

View file

@ -5,5 +5,5 @@ FastRender.onAllRoutes(function() {
}); });
FastRender.route('/b/:id/:slug', function({ id }) { FastRender.route('/b/:id/:slug', function({ id }) {
this.subscribe('board', id); this.subscribe('board', id, false);
}); });