Update Global Search, Due Cards, and My Cards to use the same

code for searching and display
This commit is contained in:
John R. Supplee 2021-03-01 01:49:56 +02:00
parent 8181074238
commit a1bda1169e
7 changed files with 266 additions and 637 deletions

View file

@ -22,13 +22,17 @@ template(name="dueCardsModalTitle")
template(name="dueCards") template(name="dueCards")
if currentUser if currentUser
if isPageReady.get if searching.get
.wrapper
.due-cards-dueat-list-wrapper
each card in dueCardsList
+resultCard(card)
else
+spinner +spinner
else if hasResults.get
.global-search-results-list-wrapper
if hasQueryErrors.get
div
each msg in errorMessages
span.global-search-error-messages
= msg
else
+resultsPaged(this)
template(name="dueCardsViewChangePopup") template(name="dueCardsViewChangePopup")
if currentUser if currentUser

View file

@ -1,3 +1,5 @@
import { CardSearchPagedComponent } from '../../lib/cardSearch';
const subManager = new SubsManager(); const subManager = new SubsManager();
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
@ -40,102 +42,43 @@ BlazeComponent.extendComponent({
}, },
}).register('dueCardsViewChangePopup'); }).register('dueCardsViewChangePopup');
BlazeComponent.extendComponent({ class DueCardsComponent extends CardSearchPagedComponent {
onCreated() { onCreated() {
this.isPageReady = new ReactiveVar(false); super.onCreated();
this.autorun(() => { const queryParams = {
const handle = subManager.subscribe( has: [{ field: 'dueAt', exists: true }],
'dueCards', limit: 5,
Utils.dueCardsView() === 'all', skip: 0,
); sort: { name: 'dueAt', order: 'des' },
Tracker.nonreactive(() => { };
Tracker.autorun(() => {
this.isPageReady.set(handle.ready()); if (Utils.dueCardsView() !== 'all') {
}); queryParams.users = [Meteor.user().username];
}); }
});
Meteor.subscribe('setting'); this.autorunGlobalSearch(queryParams);
}, }
dueCardsView() { dueCardsView() {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
//console.log('sort:', Utils.dueCardsView()); //console.log('sort:', Utils.dueCardsView());
return Utils.dueCardsView(); return Utils.dueCardsView();
}, }
sortByBoard() { sortByBoard() {
return this.dueCardsView() === 'board'; return this.dueCardsView() === 'board';
}, }
dueCardsList() { dueCardsList() {
const allUsers = Utils.dueCardsView() === 'all'; const results = this.getResults();
console.log('results:', results);
const user = Meteor.user();
const archivedBoards = [];
Boards.find({ archived: true }).forEach(board => {
archivedBoards.push(board._id);
});
const permiitedBoards = [];
let selector = {
archived: false,
};
// for every user including 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 = []; const cards = [];
if (results) {
// eslint-disable-next-line no-console results.forEach(card => {
// console.log('cards selector:', selector); cards.push(card);
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) => { cards.sort((a, b) => {
const x = a.dueAt === null ? Date('2100-12-31') : a.dueAt; const x = a.dueAt === null ? Date('2100-12-31') : a.dueAt;
@ -148,7 +91,9 @@ BlazeComponent.extendComponent({
}); });
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('cards:', cards); console.log('cards:', cards);
return cards; return cards;
}, }
}).register('dueCards'); }
DueCardsComponent.register('dueCards');

View file

@ -10,6 +10,23 @@ template(name="globalSearchModalTitle")
i.fa.fa-keyboard-o i.fa.fa-keyboard-o
| {{_ 'globalSearch-title'}} | {{_ 'globalSearch-title'}}
template(name="resultsPaged")
h1
= resultsHeading.get
a.fa.fa-link(title="{{_ 'link-to-search' }}" href="{{ getSearchHref }}")
each card in results.get
+resultCard(card)
table.global-search-footer
tr
td.global-search-previous-page
if hasPreviousPage.get
button.js-previous-page
| {{_ 'previous-page' }}
td.global-search-next-page(align="right")
if hasNextPage.get
button.js-next-page
| {{_ 'next-page' }}
template(name="globalSearch") template(name="globalSearch")
if currentUser if currentUser
.wrapper .wrapper
@ -32,21 +49,7 @@ template(name="globalSearch")
span.global-search-error-messages span.global-search-error-messages
= msg = msg
else else
h1 +resultsPaged(this)
= resultsHeading.get
a.fa.fa-link(title="{{_ 'link-to-search' }}" href="{{ getSearchHref }}")
each card in results.get
+resultCard(card)
table.global-search-footer
tr
td.global-search-previous-page
if hasPreviousPage.get
button.js-previous-page
| {{_ 'previous-page' }}
td.global-search-next-page(align="right")
if hasNextPage.get
button.js-next-page
| {{_ 'next-page' }}
else else
.global-search-page .global-search-page
.global-search-help .global-search-help

View file

@ -1,4 +1,6 @@
const subManager = new SubsManager(); import { CardSearchPagedComponent } from '../../lib/cardSearch';
// const subManager = new SubsManager();
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
events() { events() {
@ -34,27 +36,15 @@ BlazeComponent.extendComponent({
}, },
}).register('globalSearchViewChangePopup'); }).register('globalSearchViewChangePopup');
BlazeComponent.extendComponent({ class GlobalSearchComponent extends CardSearchPagedComponent {
onCreated() { onCreated() {
this.searching = new ReactiveVar(false); super.onCreated();
this.hasResults = new ReactiveVar(false);
this.hasQueryErrors = new ReactiveVar(false);
this.query = new ReactiveVar('');
this.resultsHeading = new ReactiveVar('');
this.searchLink = new ReactiveVar(null);
this.myLists = new ReactiveVar([]); this.myLists = new ReactiveVar([]);
this.myLabelNames = new ReactiveVar([]); this.myLabelNames = new ReactiveVar([]);
this.myBoardNames = new ReactiveVar([]); this.myBoardNames = new ReactiveVar([]);
this.results = new ReactiveVar([]);
this.hasNextPage = new ReactiveVar(false);
this.hasPreviousPage = new ReactiveVar(false);
this.queryParams = null;
this.parsingErrors = []; this.parsingErrors = [];
this.resultsCount = 0;
this.totalHits = 0;
this.queryErrors = null;
this.colorMap = null; this.colorMap = null;
this.resultsPerPage = 25; this.queryParams = null;
Meteor.call('myLists', (err, data) => { Meteor.call('myLists', (err, data) => {
if (!err) { if (!err) {
@ -73,7 +63,7 @@ BlazeComponent.extendComponent({
this.myBoardNames.set(data); this.myBoardNames.set(data);
} }
}); });
}, }
onRendered() { onRendered() {
Meteor.subscribe('setting'); Meteor.subscribe('setting');
@ -87,67 +77,19 @@ BlazeComponent.extendComponent({
if (Session.get('globalQuery')) { if (Session.get('globalQuery')) {
this.searchAllBoards(Session.get('globalQuery')); this.searchAllBoards(Session.get('globalQuery'));
} }
}, }
resetSearch() { resetSearch() {
this.searching.set(false); super.resetSearch();
this.results.set([]);
this.hasResults.set(false);
this.hasQueryErrors.set(false);
this.resultsHeading.set('');
this.parsingErrors = []; this.parsingErrors = [];
this.resultsCount = 0; }
this.totalHits = 0;
this.queryErrors = null;
},
getSessionData() {
return SessionData.findOne({
userId: Meteor.userId(),
sessionId: SessionData.getSessionId(),
});
},
getResults() {
// eslint-disable-next-line no-console
// console.log('getting results');
if (this.queryParams) {
const sessionData = this.getSessionData();
// eslint-disable-next-line no-console
// console.log('selector:', sessionData.getSelector());
// console.log('session data:', sessionData);
const projection = sessionData.getProjection();
projection.skip = 0;
const cards = Cards.find({ _id: { $in: sessionData.cards } }, projection);
this.queryErrors = sessionData.errors;
if (this.queryErrors.length) {
this.hasQueryErrors.set(true);
return null;
}
if (cards) {
this.totalHits = sessionData.totalHits;
this.resultsCount = cards.count();
this.resultsStart = sessionData.lastHit - this.resultsCount + 1;
this.resultsEnd = sessionData.lastHit;
this.resultsHeading.set(this.getResultsHeading());
this.results.set(cards);
this.hasNextPage.set(sessionData.lastHit < sessionData.totalHits);
this.hasPreviousPage.set(
sessionData.lastHit - sessionData.resultsCount > 0,
);
}
}
this.resultsCount = 0;
return null;
},
errorMessages() { errorMessages() {
if (this.parsingErrors.length) { if (this.parsingErrors.length) {
return this.parsingErrorMessages(); return this.parsingErrorMessages();
} }
return this.queryErrorMessages(); return this.queryErrorMessages();
}, }
parsingErrorMessages() { parsingErrorMessages() {
const messages = []; const messages = [];
@ -159,21 +101,7 @@ BlazeComponent.extendComponent({
} }
return messages; return messages;
}, }
queryErrorMessages() {
messages = [];
this.queryErrors.forEach(err => {
let value = err.color ? TAPi18n.__(`color-${err.value}`) : err.value;
if (!value) {
value = err.value;
}
messages.push(TAPi18n.__(err.tag, value));
});
return messages;
},
searchAllBoards(query) { searchAllBoards(query) {
query = query.trim(); query = query.trim();
@ -300,7 +228,7 @@ BlazeComponent.extendComponent({
let text = ''; let text = '';
while (query) { while (query) {
m = query.match(reOperator1); let m = query.match(reOperator1);
if (!m) { if (!m) {
m = query.match(reOperator2); m = query.match(reOperator2);
if (m) { if (m) {
@ -326,7 +254,7 @@ BlazeComponent.extendComponent({
// console.log('found color:', value); // console.log('found color:', value);
} }
} else if (['dueAt', 'createdAt', 'modifiedAt'].includes(operator)) { } else if (['dueAt', 'createdAt', 'modifiedAt'].includes(operator)) {
let days = parseInt(value, 10); const days = parseInt(value, 10);
let duration = null; let duration = null;
if (isNaN(days)) { if (isNaN(days)) {
// duration was specified as text // duration was specified as text
@ -335,7 +263,8 @@ BlazeComponent.extendComponent({
let date = null; let date = null;
switch (duration) { switch (duration) {
case 'week': case 'week':
let week = moment().week(); // eslint-disable-next-line no-case-declarations
const week = moment().week();
if (week === 52) { if (week === 52) {
date = moment(1, 'W'); date = moment(1, 'W');
date.set('year', date.year() + 1); date.set('year', date.year() + 1);
@ -344,7 +273,8 @@ BlazeComponent.extendComponent({
} }
break; break;
case 'month': case 'month':
let month = moment().month(); // eslint-disable-next-line no-case-declarations
const month = moment().month();
// .month() is zero indexed // .month() is zero indexed
if (month === 11) { if (month === 11) {
date = moment(1, 'M'); date = moment(1, 'M');
@ -354,7 +284,8 @@ BlazeComponent.extendComponent({
} }
break; break;
case 'quarter': case 'quarter':
let quarter = moment().quarter(); // eslint-disable-next-line no-case-declarations
const quarter = moment().quarter();
if (quarter === 4) { if (quarter === 4) {
date = moment(1, 'Q'); date = moment(1, 'Q');
date.set('year', date.year() + 1); date.set('year', date.year() + 1);
@ -384,22 +315,20 @@ BlazeComponent.extendComponent({
}); });
value = null; value = null;
} }
} else if (operator === 'dueAt') {
value = {
operator: '$lt',
value: moment(moment().format('YYYY-MM-DD'))
.add(days + 1, duration ? duration : 'days')
.format(),
};
} else { } else {
if (operator === 'dueAt') { value = {
value = { operator: '$gte',
operator: '$lt', value: moment(moment().format('YYYY-MM-DD'))
value: moment(moment().format('YYYY-MM-DD')) .subtract(days, duration ? duration : 'days')
.add(days + 1, duration ? duration : 'days') .format(),
.format(), };
};
} else {
value = {
operator: '$gte',
value: moment(moment().format('YYYY-MM-DD'))
.subtract(days, duration ? duration : 'days')
.format(),
};
}
} }
} else if (operator === 'sort') { } else if (operator === 'sort') {
let negated = false; let negated = false;
@ -502,81 +431,11 @@ BlazeComponent.extendComponent({
return; return;
} }
this.autorun(() => { this.autorunGlobalSearch(params);
const handle = Meteor.subscribe( }
'globalSearch',
SessionData.getSessionId(),
params,
);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
if (handle.ready()) {
this.getResults();
this.searching.set(false);
this.hasResults.set(true);
}
});
});
});
},
nextPage() {
const sessionData = this.getSessionData();
this.autorun(() => {
const handle = Meteor.subscribe('nextPage', sessionData.sessionId);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
if (handle.ready()) {
this.getResults();
this.searching.set(false);
this.hasResults.set(true);
}
});
});
});
},
previousPage() {
const sessionData = this.getSessionData();
this.autorun(() => {
const handle = Meteor.subscribe('previousPage', sessionData.sessionId);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
if (handle.ready()) {
this.getResults();
this.searching.set(false);
this.hasResults.set(true);
}
});
});
});
},
getResultsHeading() {
if (this.resultsCount === 0) {
return TAPi18n.__('no-cards-found');
} else if (this.resultsCount === 1) {
return TAPi18n.__('one-card-found');
} else if (this.resultsCount === this.totalHits) {
return TAPi18n.__('n-cards-found', this.resultsCount);
}
return TAPi18n.__('n-n-of-n-cards-found', {
start: this.resultsStart,
end: this.resultsEnd,
total: this.totalHits,
});
},
getSearchHref() {
const baseUrl = window.location.href.replace(/([?#].*$|\s*$)/, '');
return `${baseUrl}?q=${encodeURIComponent(this.query.get())}`;
},
searchInstructions() { searchInstructions() {
tags = { const tags = {
operator_board: TAPi18n.__('operator-board'), operator_board: TAPi18n.__('operator-board'),
operator_list: TAPi18n.__('operator-list'), operator_list: TAPi18n.__('operator-list'),
operator_swimlane: TAPi18n.__('operator-swimlane'), operator_swimlane: TAPi18n.__('operator-swimlane'),
@ -654,7 +513,7 @@ BlazeComponent.extendComponent({
[ [
'globalSearch-instructions-operator-has', 'globalSearch-instructions-operator-has',
'globalSearch-instructions-operator-sort', 'globalSearch-instructions-operator-sort',
'globalSearch-instructions-operator-limit' 'globalSearch-instructions-operator-limit',
].forEach(instruction => { ].forEach(instruction => {
text += `\n* ${TAPi18n.__(instruction, tags)}`; text += `\n* ${TAPi18n.__(instruction, tags)}`;
}); });
@ -672,7 +531,7 @@ BlazeComponent.extendComponent({
}); });
return text; return text;
}, }
labelColors() { labelColors() {
return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map( return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map(
@ -680,23 +539,16 @@ BlazeComponent.extendComponent({
return { color, name: TAPi18n.__(`color-${color}`) }; return { color, name: TAPi18n.__(`color-${color}`) };
}, },
); );
}, }
events() { events() {
return [ return [
{ {
...super.events()[0],
'submit .js-search-query-form'(evt) { 'submit .js-search-query-form'(evt) {
evt.preventDefault(); evt.preventDefault();
this.searchAllBoards(evt.target.searchQuery.value); this.searchAllBoards(evt.target.searchQuery.value);
}, },
'click .js-next-page'(evt) {
evt.preventDefault();
this.nextPage();
},
'click .js-previous-page'(evt) {
evt.preventDefault();
this.previousPage();
},
'click .js-label-color'(evt) { 'click .js-label-color'(evt) {
evt.preventDefault(); evt.preventDefault();
const input = document.getElementById('global-search-input'); const input = document.getElementById('global-search-input');
@ -739,5 +591,7 @@ BlazeComponent.extendComponent({
}, },
}, },
]; ];
}, }
}).register('globalSearch'); }
GlobalSearchComponent.register('globalSearch');

View file

@ -24,14 +24,16 @@ template(name="myCardsModalTitle")
template(name="myCards") template(name="myCards")
if currentUser if currentUser
if isPageReady.get if searching.get
+spinner
else
.wrapper .wrapper
if $eq myCardsSort 'board' if $eq myCardsSort 'board'
each board in myCardsList each board in myCardsList
.my-cards-board-wrapper .my-cards-board-wrapper
.my-cards-board-title(class=board.colorClass, id="header") .my-cards-board-title(class=board.colorClass, id="header")
a(href=board.absoluteUrl) a(href=board.absoluteUrl)
+viewer +viewer
= board.title = board.title
each swimlane in board.mySwimlanes each swimlane in board.mySwimlanes
.my-cards-swimlane-title(class="{{#if swimlane.colorClass}}{{ swimlane.colorClass }}{{else}}swimlane-default-color{{/if}}") .my-cards-swimlane-title(class="{{#if swimlane.colorClass}}{{ swimlane.colorClass }}{{else}}swimlane-default-color{{/if}}")
@ -50,8 +52,6 @@ template(name="myCards")
.my-cards-dueat-list-wrapper .my-cards-dueat-list-wrapper
each card in myDueCardsList each card in myDueCardsList
+resultCard(card) +resultCard(card)
else
+spinner
template(name="myCardsSortChangePopup") template(name="myCardsSortChangePopup")
if currentUser if currentUser

View file

@ -1,3 +1,5 @@
import {CardSearchPagedComponent} from "../../lib/cardSearch";
const subManager = new SubsManager(); const subManager = new SubsManager();
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
@ -42,177 +44,139 @@ BlazeComponent.extendComponent({
}, },
}).register('myCardsSortChangePopup'); }).register('myCardsSortChangePopup');
BlazeComponent.extendComponent({ class MyCardsComponent extends CardSearchPagedComponent {
onCreated() { onCreated() {
this.isPageReady = new ReactiveVar(false); super.onCreated();
this.autorun(() => { const queryParams = {
const handle = subManager.subscribe('myCards'); users: [Meteor.user().username],
Tracker.nonreactive(() => { sort: { name: 'dueAt', order: 'des' },
Tracker.autorun(() => { };
this.isPageReady.set(handle.ready());
}); this.autorunGlobalSearch(queryParams);
});
});
Meteor.subscribe('setting'); Meteor.subscribe('setting');
}, }
myCardsSort() { myCardsSort() {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
//console.log('sort:', Utils.myCardsSort()); //console.log('sort:', Utils.myCardsSort());
return Utils.myCardsSort(); return Utils.myCardsSort();
}, }
sortByBoard() { sortByBoard() {
return this.myCardsSort() === 'board'; return this.myCardsSort() === 'board';
}, }
myCardsList() { myCardsList() {
const userId = Meteor.userId();
const boards = []; const boards = [];
let board = null; let board = null;
let swimlane = null; let swimlane = null;
let list = null; let list = null;
const cursor = Cards.find( const cursor = this.getResults();
{
$or: [{ members: userId }, { assignees: userId }],
archived: false,
},
{
sort: {
boardId: 1,
swimlaneId: 1,
listId: 1,
sort: 1,
},
},
);
let newBoard = false; if (cursor) {
let newSwimlane = false; let newBoard = false;
let newList = false; let newSwimlane = false;
let newList = false;
cursor.forEach(card => { cursor.forEach(card => {
// eslint-disable-next-line no-console
// console.log('card:', card.title);
if (list === null || card.listId !== list._id) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('new list'); // console.log('card:', card.title);
list = card.getList(); if (list === null || card.listId !== list._id) {
if (list.archived) { // eslint-disable-next-line no-console
list = null; // console.log('new list');
return; list = card.getList();
if (list.archived) {
list = null;
return;
}
list.myCards = [card];
newList = true;
} }
list.myCards = [card]; if (swimlane === null || card.swimlaneId !== swimlane._id) {
newList = true; // eslint-disable-next-line no-console
} // console.log('new swimlane');
if (swimlane === null || card.swimlaneId !== swimlane._id) { swimlane = card.getSwimlane();
// eslint-disable-next-line no-console if (swimlane.archived) {
// console.log('new swimlane'); swimlane = null;
swimlane = card.getSwimlane(); return;
if (swimlane.archived) { }
swimlane = null; swimlane.myLists = [list];
return; newSwimlane = true;
} }
swimlane.myLists = [list]; if (board === null || card.boardId !== board._id) {
newSwimlane = true; // eslint-disable-next-line no-console
} // console.log('new board');
if (board === null || card.boardId !== board._id) { board = card.getBoard();
// eslint-disable-next-line no-console if (board.archived) {
// console.log('new board'); board = null;
board = card.getBoard(); return;
if (board.archived) { }
board = null; // eslint-disable-next-line no-console
return; // console.log('board:', b, b._id, b.title);
board.mySwimlanes = [swimlane];
newBoard = true;
} }
// eslint-disable-next-line no-console
// console.log('board:', b, b._id, b.title);
board.mySwimlanes = [swimlane];
newBoard = true;
}
if (newBoard) { if (newBoard) {
boards.push(board); boards.push(board);
} else if (newSwimlane) { } else if (newSwimlane) {
board.mySwimlanes.push(swimlane); board.mySwimlanes.push(swimlane);
} else if (newList) { } else if (newList) {
swimlane.myLists.push(list); swimlane.myLists.push(list);
} else { } else {
list.myCards.push(card); list.myCards.push(card);
} }
newBoard = false; newBoard = false;
newSwimlane = false; newSwimlane = false;
newList = false; newList = false;
}); });
// sort the data structure // sort the data structure
boards.forEach(board => { boards.forEach(board => {
board.mySwimlanes.forEach(swimlane => { board.mySwimlanes.forEach(swimlane => {
swimlane.myLists.forEach(list => { swimlane.myLists.forEach(list => {
list.myCards.sort((a, b) => { list.myCards.sort((a, b) => {
return a.sort - b.sort;
});
});
swimlane.myLists.sort((a, b) => {
return a.sort - b.sort; return a.sort - b.sort;
}); });
}); });
swimlane.myLists.sort((a, b) => { board.mySwimlanes.sort((a, b) => {
return a.sort - b.sort; return a.sort - b.sort;
}); });
}); });
board.mySwimlanes.sort((a, b) => {
return a.sort - b.sort; boards.sort((a, b) => {
let x = a.sort;
let y = b.sort;
// show the template board last
if (a.type === 'template-container') {
x = 99999999;
} else if (b.type === 'template-container') {
y = 99999999;
}
return x - y;
}); });
});
boards.sort((a, b) => { // eslint-disable-next-line no-console
let x = a.sort; // console.log('boards:', boards);
let y = b.sort; return boards;
}
// show the template board last return [];
if (a.type === 'template-container') { }
x = 99999999;
} else if (b.type === 'template-container') {
y = 99999999;
}
return x - y;
});
// eslint-disable-next-line no-console
// console.log('boards:', boards);
return boards;
},
myDueCardsList() { myDueCardsList() {
const userId = Meteor.userId(); const cursor = this.getResults();
const cursor = Cards.find(
{
$or: [{ members: userId }, { assignees: userId }],
archived: false,
},
{
sort: {
dueAt: -1,
boardId: 1,
swimlaneId: 1,
listId: 1,
sort: 1,
},
},
);
// eslint-disable-next-line no-console
// console.log('cursor:', cursor);
const cards = []; const cards = [];
cursor.forEach(card => { cursor.forEach(card => {
if ( cards.push(card);
!card.getBoard().archived &&
!card.getSwimlane().archived &&
!card.getList().archived
) {
cards.push(card);
}
}); });
cards.sort((a, b) => { cards.sort((a, b) => {
@ -228,23 +192,6 @@ BlazeComponent.extendComponent({
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('cursor:', cards); // console.log('cursor:', cards);
return cards; return cards;
}, }
}
events() { MyCardsComponent.register('myCards');
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('myCards');

View file

@ -5,175 +5,38 @@ Meteor.publish('card', cardId => {
return Cards.find({ _id: cardId }); return Cards.find({ _id: cardId });
}); });
Meteor.publish('myCards', function() { Meteor.publish('myCards', function(sessionId) {
const userId = Meteor.userId();
const archivedBoards = []; const queryParams = {
Boards.find({ archived: true }).forEach(board => { users: [Meteor.user().username],
archivedBoards.push(board._id); // limit: 25,
}); skip: 0,
// sort: { name: 'dueAt', order: 'des' },
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 },
swimlaneId: { $nin: archivedSwimlanes },
listId: { $nin: archivedLists },
$or: [{ members: userId }, { assignees: userId }],
}; };
const cards = Cards.find(selector, { return buildQuery(sessionId, queryParams);
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 = [];
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 } }, { fields: Users.safeFields }),
];
}); });
Meteor.publish('dueCards', function(allUsers = false) { // Meteor.publish('dueCards', function(sessionId, allUsers = false) {
check(allUsers, Boolean); // check(sessionId, String);
// check(allUsers, Boolean);
// eslint-disable-next-line no-console //
// console.log('all users:', allUsers); // // eslint-disable-next-line no-console
// // console.log('all users:', allUsers);
const user = Users.findOne({ _id: this.userId }); //
// const queryParams = {
const archivedBoards = []; // has: [{ field: 'dueAt', exists: true }],
Boards.find({ archived: true }).forEach(board => { // limit: 25,
archivedBoards.push(board._id); // skip: 0,
}); // sort: { name: 'dueAt', order: 'des' },
// };
const permiitedBoards = []; //
let selector = { // if (!allUsers) {
archived: false, // queryParams.users = [Meteor.user().username];
}; // }
//
selector.$or = [ // return buildQuery(sessionId, queryParams);
{ 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 = [];
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 } }, { fields: Users.safeFields }),
];
});
Meteor.publish('globalSearch', function(sessionId, queryParams) { Meteor.publish('globalSearch', function(sessionId, queryParams) {
check(sessionId, String); check(sessionId, String);
@ -182,9 +45,11 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('queryParams:', queryParams); // console.log('queryParams:', queryParams);
return buildQuery(sessionId, queryParams);
});
function buildQuery(sessionId, queryParams) {
const userId = Meteor.userId(); const userId = Meteor.userId();
// eslint-disable-next-line no-console
// console.log('userId:', userId);
const errors = new (class { const errors = new (class {
constructor() { constructor() {
@ -267,7 +132,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
let archived = false; let archived = false;
let endAt = null; let endAt = null;
if (queryParams.status.length) { if (queryParams.status && queryParams.status.length) {
queryParams.status.forEach(status => { queryParams.status.forEach(status => {
if (status === 'archived') { if (status === 'archived') {
archived = true; archived = true;
@ -320,7 +185,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
selector.endAt = endAt; selector.endAt = endAt;
} }
if (queryParams.boards.length) { if (queryParams.boards && queryParams.boards.length) {
const queryBoards = []; const queryBoards = [];
queryParams.boards.forEach(query => { queryParams.boards.forEach(query => {
const boards = Boards.userSearch(userId, { const boards = Boards.userSearch(userId, {
@ -338,7 +203,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
selector.boardId.$in = queryBoards; selector.boardId.$in = queryBoards;
} }
if (queryParams.swimlanes.length) { if (queryParams.swimlanes && queryParams.swimlanes.length) {
const querySwimlanes = []; const querySwimlanes = [];
queryParams.swimlanes.forEach(query => { queryParams.swimlanes.forEach(query => {
const swimlanes = Swimlanes.find({ const swimlanes = Swimlanes.find({
@ -360,7 +225,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
selector.swimlaneId.$in = querySwimlanes; selector.swimlaneId.$in = querySwimlanes;
} }
if (queryParams.lists.length) { if (queryParams.lists && queryParams.lists.length) {
const queryLists = []; const queryLists = [];
queryParams.lists.forEach(query => { queryParams.lists.forEach(query => {
const lists = Lists.find({ const lists = Lists.find({
@ -382,7 +247,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
selector.listId.$in = queryLists; selector.listId.$in = queryLists;
} }
if (queryParams.comments.length) { if (queryParams.comments && queryParams.comments.length) {
const cardIds = CardComments.textSearch(userId, queryParams.comments).map( const cardIds = CardComments.textSearch(userId, queryParams.comments).map(
com => { com => {
return com.cardId; return com.cardId;
@ -398,15 +263,15 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
['dueAt', 'createdAt', 'modifiedAt'].forEach(field => { ['dueAt', 'createdAt', 'modifiedAt'].forEach(field => {
if (queryParams[field]) { if (queryParams[field]) {
selector[field] = {}; selector[field] = {};
selector[field][queryParams[field]['operator']] = new Date( selector[field][queryParams[field].operator] = new Date(
queryParams[field]['value'], queryParams[field].value,
); );
} }
}); });
const queryMembers = []; const queryMembers = [];
const queryAssignees = []; const queryAssignees = [];
if (queryParams.users.length) { if (queryParams.users && queryParams.users.length) {
queryParams.users.forEach(query => { queryParams.users.forEach(query => {
const users = Users.find({ const users = Users.find({
username: query, username: query,
@ -422,7 +287,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
}); });
} }
if (queryParams.members.length) { if (queryParams.members && queryParams.members.length) {
queryParams.members.forEach(query => { queryParams.members.forEach(query => {
const users = Users.find({ const users = Users.find({
username: query, username: query,
@ -437,7 +302,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
}); });
} }
if (queryParams.assignees.length) { if (queryParams.assignees && queryParams.assignees.length) {
queryParams.assignees.forEach(query => { queryParams.assignees.forEach(query => {
const users = Users.find({ const users = Users.find({
username: query, username: query,
@ -465,7 +330,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
selector.assignees = { $in: queryAssignees }; selector.assignees = { $in: queryAssignees };
} }
if (queryParams.labels.length) { if (queryParams.labels && queryParams.labels.length) {
queryParams.labels.forEach(label => { queryParams.labels.forEach(label => {
const queryLabels = []; const queryLabels = [];
@ -516,16 +381,26 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
}); });
} }
if (queryParams.has.length) { if (queryParams.has && queryParams.has.length) {
queryParams.has.forEach(has => { queryParams.has.forEach(has => {
switch (has.field) { switch (has.field) {
case 'attachment': case 'attachment':
const attachments = Attachments.find({}, { fields: { cardId: 1 } }); selector.$and.push({
selector.$and.push({ _id: { $in: attachments.map(a => a.cardId) } }); _id: {
$in: Attachments.find({}, { fields: { cardId: 1 } }).map(
a => a.cardId,
),
},
});
break; break;
case 'checklist': case 'checklist':
const checklists = Checklists.find({}, { fields: { cardId: 1 } }); selector.$and.push({
selector.$and.push({ _id: { $in: checklists.map(a => a.cardId) } }); _id: {
$in: Checklists.find({}, { fields: { cardId: 1 } }).map(
a => a.cardId,
),
},
});
break; break;
case 'description': case 'description':
case 'startAt': case 'startAt':
@ -677,7 +552,7 @@ Meteor.publish('globalSearch', function(sessionId, queryParams) {
// console.log('projection:', projection); // console.log('projection:', projection);
return findCards(sessionId, selector, projection, errors); return findCards(sessionId, selector, projection, errors);
}); }
Meteor.publish('brokenCards', function() { Meteor.publish('brokenCards', function() {
const user = Users.findOne({ _id: this.userId }); const user = Users.findOne({ _id: this.userId });
@ -773,7 +648,8 @@ function findCards(sessionId, selector, projection, errors = null) {
const userId = Meteor.userId(); const userId = Meteor.userId();
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('selector:', selector); console.log('selector:', selector);
console.log('selector.$and:', selector.$and);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('projection:', projection); // console.log('projection:', projection);
let cards; let cards;
@ -879,5 +755,5 @@ function findCards(sessionId, selector, projection, errors = null) {
]; ];
} }
return [SessionData.find({ userId: userId, sessionId })]; return [SessionData.find({ userId, sessionId })];
} }