Prechádzať zdrojové kódy

Global search limited working prototype

* added publication
* need to filter cards on client side
John R. Supplee 4 rokov pred
rodič
commit
01bd94d2b3

+ 31 - 7
client/components/main/globalSearch.jade

@@ -9,25 +9,49 @@ template(name="globalSearchModalTitle")
     | {{_ 'globalSearch-title'}}
     | {{_ 'globalSearch-title'}}
 
 
 template(name="globalSearch")
 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
     +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")
 template(name="globalSearchViewChangePopup")
   ul.pop-over-list
   ul.pop-over-list
     li
     li
       with "globalSearchViewChange-choice-me"
       with "globalSearchViewChange-choice-me"
-        a.js-due-cards-view-me
+        a.js-global-search-view-me
           i.fa.fa-user.colorful
           i.fa.fa-user.colorful
           | {{_ 'globalSearchViewChange-choice-me'}}
           | {{_ 'globalSearchViewChange-choice-me'}}
           if $eq Utils.globalSearchView "me"
           if $eq Utils.globalSearchView "me"
             i.fa.fa-check
             i.fa.fa-check
     li
     li
       with "globalSearchViewChange-choice-all"
       with "globalSearchViewChange-choice-all"
-        a.js-due-cards-view-all
+        a.js-global-search-view-all
           i.fa.fa-users.colorful
           i.fa.fa-users.colorful
           | {{_ 'globalSearchViewChange-choice-all'}}
           | {{_ 'globalSearchViewChange-choice-all'}}
           span.sub-name
           span.sub-name

+ 22 - 2
client/components/main/globalSearch.js

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

+ 11 - 11
client/components/main/globalSearch.styl

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

+ 122 - 0
server/publications/cards.js

@@ -174,3 +174,125 @@ Meteor.publish('dueCards', function(allUsers = false) {
     Users.find({ _id: { $in: users } }),
     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 } }),
+  ];
+});