Global search limited working prototype

* added publication
* need to filter cards on client side
This commit is contained in:
John R. Supplee 2021-01-10 22:58:29 +02:00
parent 5913a4af1b
commit 01bd94d2b3
4 changed files with 186 additions and 20 deletions

View file

@ -9,25 +9,49 @@ template(name="globalSearchModalTitle")
| {{_ 'globalSearch-title'}}
template(name="globalSearch")
if isPageReady.get
.wrapper
form.js-search-query-form
input(type="text" name="searchQuery" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
else
.wrapper
form.js-search-query-form
input(type="text" name="searchQuery" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
if searching.get
+spinner
else if hasResults.get
.global-search-dueat-list-wrapper
h1 Results
each card in results
.global-search-card-wrapper
a.minicard-wrapper.card-title(href=card.absoluteUrl)
+minicard(card)
ul.global-search-context-list
li.global-search-context(title="{{_ 'board'}}")
+viewer
= card.getBoard.title
li.global-search-context.global-search-context-separator
= ' '
| {{_ 'context-separator'}}
= ' '
li.global-search-context(title="{{_ 'swimlane'}}")
+viewer
= card.getSwimlane.title
li.global-search-context
= ' '
| {{_ 'context-separator'}}
= ' '
li.global-search-context(title="{{_ 'list'}}")
+viewer
= card.getList.title
template(name="globalSearchViewChangePopup")
ul.pop-over-list
li
with "globalSearchViewChange-choice-me"
a.js-due-cards-view-me
a.js-global-search-view-me
i.fa.fa-user.colorful
| {{_ 'globalSearchViewChange-choice-me'}}
if $eq Utils.globalSearchView "me"
i.fa.fa-check
li
with "globalSearchViewChange-choice-all"
a.js-due-cards-view-all
a.js-global-search-view-all
i.fa.fa-users.colorful
| {{_ 'globalSearchViewChange-choice-all'}}
span.sub-name

View file

@ -37,6 +37,8 @@ BlazeComponent.extendComponent({
BlazeComponent.extendComponent({
onCreated() {
this.isPageReady = new ReactiveVar(true);
this.searching = new ReactiveVar(false);
this.hasResults = new ReactiveVar(false);
this.query = new ReactiveVar('');
// this.autorun(() => {
@ -50,16 +52,24 @@ BlazeComponent.extendComponent({
Meteor.subscribe('setting');
},
results() {
return Cards.find();
},
events() {
return [
{
'submit .js-search-query-form'(evt) {
evt.preventDefault();
this.query.set(evt.target.searchQuery.value);
// eslint-disable-next-line no-console
console.log('query:', this.query.get());
this.searching.set(true);
this.hasResults.set(false);
let query = this.query.get();
// eslint-disable-next-line no-console
console.log('query:', query);
const reUser = /^@(?<user>\w+)(\s+|$)/;
const reLabel = /^#(?<label>\w+)(\s+|$)/;
const reOperator1 = /^(?<operator>\w+):(?<value>\w+)(\s+|$)/;
@ -139,6 +149,16 @@ BlazeComponent.extendComponent({
console.log('selector:', selector);
// eslint-disable-next-line no-console
console.log('text:', text);
this.autorun(() => {
const handle = subManager.subscribe('globalSearch', selector);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
this.searching.set(!handle.ready());
this.hasResults.set(handle.ready());
});
});
});
},
},
];

View file

@ -1,4 +1,4 @@
.due-cards-board-wrapper
.global-search-board-wrapper
border-radius: 8px
//padding: 0.5rem
min-width: 400px
@ -9,14 +9,14 @@
margin-right: auto
margin-left: auto
.due-cards-board-title
.global-search-board-title
font-size: 1.4rem
font-weight: bold
padding: 0.5rem
background-color: grey
color: white
.due-cards-swimlane-title
.global-search-swimlane-title
font-size: 1.1rem
font-weight: bold
padding: 0.5rem
@ -30,7 +30,7 @@
.swimlane-default-color
background-color: lightgrey
.due-cards-list-title
.global-search-list-title
font-weight: bold
font-size: 1.1rem
//padding-bottom: 0
@ -38,7 +38,7 @@
text-align: center
margin-bottom: 0.7rem
.due-cards-list-wrapper
.global-search-list-wrapper
margin: 1rem
border-radius: 5px
padding: 1.5rem
@ -47,23 +47,23 @@
min-width: 250px
max-width: 350px
.due-cards-card-wrapper
.global-search-card-wrapper
margin-top: 0
margin-bottom: 10px
.due-cards-dueat-list-wrapper
.global-search-dueat-list-wrapper
max-width: 500px
margin-right: auto
margin-left: auto
.due-cards-field-name
.global-search-field-name
font-weight: bold
.due-cards-context
.global-search-context
display: inline-block
.due-cards-context-separator
.global-search-context-separator
font-weight: bold
.due-cards-context-list
.global-search-context-list
margin-bottom: 0.7rem

View file

@ -174,3 +174,125 @@ Meteor.publish('dueCards', function(allUsers = false) {
Users.find({ _id: { $in: users } }),
];
});
Meteor.publish('globalSearch', function(queryParams) {
check(queryParams, Object);
// eslint-disable-next-line no-console
console.log('selector:', queryParams);
const user = Users.findOne(this.userId);
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);
});
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 } } },
];
}
if (queryParams.boards.length) {
selector.title = { $in: [] };
queryParams.boards.forEach(term => {
selector.title.$in.push(term);
});
}
Boards.find(selector).forEach(board => {
permiitedBoards.push(board._id);
});
const searchLists = [];
if (queryParams.lists.length) {
selector = {
archived: false,
title: { $in: [] },
};
queryParams.lists.forEach(term => {
selector.title.$in.push(term);
});
// eslint-disable-next-line no-console
console.log('search list selector:', selector);
Lists.find(selector).forEach(list => {
searchLists.push(list._id);
});
// eslint-disable-next-line no-console
console.log('search lists:', searchLists);
}
selector = {
archived: false,
boardId: { $nin: archivedBoards, $in: permiitedBoards },
swimlaneId: { $nin: archivedSwimlanes },
listId: { $nin: archivedLists },
};
if (searchLists.length) {
selector.listId.$in = searchLists;
}
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 } }),
];
});