Bläddra i källkod

Fix list view issues. Allow creation of boards from templates

Andrés Manelli 6 år sedan
förälder
incheckning
dc7286a0ef

+ 1 - 1
client/components/boards/boardBody.jade

@@ -27,7 +27,7 @@ template(name="boardBody")
         each currentBoard.swimlanes
           +swimlane(this)
       else if isViewLists
-        +listsGroup
+        +listsGroup(currentBoard)
       else if isViewCalendar
         +calendarView
 

+ 4 - 1
client/components/boards/boardHeader.jade

@@ -277,7 +277,10 @@ template(name="createBoard")
     input.primary.wide(type="submit" value="{{_ 'create'}}")
     span.quiet
       | {{_ 'or'}}
-      a.js-import-board {{_ 'import-board'}}
+      a.js-import-board {{_ 'import'}}
+    span.quiet
+      | /
+      a.js-board-template {{_ 'template'}}
 
 template(name="chooseBoardSource")
   ul.pop-over-list

+ 1 - 0
client/components/boards/boardHeader.js

@@ -304,6 +304,7 @@ const CreateBoard = BlazeComponent.extendComponent({
       'click .js-import': Popup.open('boardImportBoard'),
       submit: this.onSubmit,
       'click .js-import-board': Popup.open('chooseBoardSource'),
+      'click .js-board-template': Popup.open('searchElement'),
     }];
   },
 }).register('createBoardPopup');

+ 8 - 0
client/components/boards/miniboard.jade

@@ -0,0 +1,8 @@
+template(name="miniboard")
+  .minicard(
+    class="minicard-{{colorClass}}")
+    .minicard-title
+      .handle
+        .fa.fa-arrows
+      +viewer
+        = title

+ 12 - 5
client/components/lists/listBody.jade

@@ -103,16 +103,23 @@ template(name="searchElementPopup")
     input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
   .list-body.js-perfect-scrollbar.search-card-results
     .minicards.clearfix.js-minicards
-      each results
-        if isListTemplateSearch
+      if isBoardTemplateSearch
+        each results
+          a.minicard-wrapper.js-minicard
+            +miniboard(this)
+      if isListTemplateSearch
+        each results
           a.minicard-wrapper.js-minicard
             +minilist(this)
-        if isSwimlaneTemplateSearch
+      if isSwimlaneTemplateSearch
+        each results
           a.minicard-wrapper.js-minicard
             +miniswimlane(this)
-        if isCardTemplateSearch
+      if isCardTemplateSearch
+        each results
           a.minicard-wrapper.js-minicard
             +minicard(this)
-        unless isTemplateSearch
+      unless isTemplateSearch
+        each results
           a.minicard-wrapper.js-minicard
             +minicard(this)

+ 38 - 17
client/components/lists/listBody.js

@@ -527,7 +527,11 @@ BlazeComponent.extendComponent({
     this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template');
     this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template');
     this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu');
-    this.isTemplateSearch = this.isCardTemplateSearch || this.isListTemplateSearch || this.isSwimlaneTemplateSearch;
+    this.isBoardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-add-board');
+    this.isTemplateSearch = this.isCardTemplateSearch ||
+      this.isListTemplateSearch ||
+      this.isSwimlaneTemplateSearch ||
+      this.isBoardTemplateSearch;
     let board = {};
     if (this.isTemplateSearch) {
       board = Boards.findOne(Meteor.user().profile.templatesBoardId);
@@ -548,23 +552,26 @@ BlazeComponent.extendComponent({
     subManager.subscribe('board', boardId);
     this.selectedBoardId = new ReactiveVar(boardId);
 
-    this.boardId = Session.get('currentBoard');
-    // In order to get current board info
-    subManager.subscribe('board', this.boardId);
-    // List where to insert card
-    const list = $(Popup._getTopStack().openerElement).closest('.js-list');
-    this.listId = Blaze.getData(list[0])._id;
-    // Swimlane where to insert card
-    const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
-    this.swimlaneId = '';
-    if (Meteor.user().profile.boardView === 'board-view-swimlanes')
-      this.swimlaneId = Blaze.getData(swimlane[0])._id;
-    else
-      this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+    if (!this.isBoardTemplateSearch) {
+      this.boardId = Session.get('currentBoard');
+      // In order to get current board info
+      subManager.subscribe('board', this.boardId);
+      this.swimlaneId = '';
+      // Swimlane where to insert card
+      const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
+      if (Meteor.user().profile.boardView === 'board-view-swimlanes')
+        this.swimlaneId = Blaze.getData(swimlane[0])._id;
+      else
+        this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+      // List where to insert card
+      const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+      this.listId = Blaze.getData(list[0])._id;
+    }
     this.term = new ReactiveVar('');
   },
 
   boards() {
+    console.log('booom');
     const boards = Boards.find({
       archived: false,
       'members.userId': Meteor.userId(),
@@ -587,6 +594,12 @@ BlazeComponent.extendComponent({
       return board.searchLists(this.term.get());
     } else if (this.isSwimlaneTemplateSearch) {
       return board.searchSwimlanes(this.term.get());
+    } else if (this.isBoardTemplateSearch) {
+      const boards = board.searchBoards(this.term.get());
+      boards.forEach((board) => {
+        subManager.subscribe('board', board.linkedId);
+      });
+      return boards;
     } else {
       return [];
     }
@@ -605,11 +618,11 @@ BlazeComponent.extendComponent({
       'click .js-minicard'(evt) {
         // 0. Common
         const element = Blaze.getData(evt.currentTarget);
-        element.boardId = this.boardId;
         let _id = '';
         if (!this.isTemplateSearch || this.isCardTemplateSearch) {
           // Card insertion
           // 1. Common
+          element.boardId = this.boardId;
           element.listId = this.listId;
           element.swimlaneId = this.swimlaneId;
           element.sort = Lists.findOne(this.listId).cards().count();
@@ -620,7 +633,7 @@ BlazeComponent.extendComponent({
             _id = element.copy();
             // 1.B Linked card
           } else {
-            element._id = null;
+            delete element._id;
             element.type = 'cardType-linkedCard';
             element.linkedId = element.linkedId || element._id;
             _id = Cards.insert(element);
@@ -628,14 +641,22 @@ BlazeComponent.extendComponent({
           Filter.addException(_id);
           // List insertion
         } else if (this.isListTemplateSearch) {
+          element.boardId = this.boardId;
           element.sort = Swimlanes.findOne(this.swimlaneId).lists().count();
           element.type = 'list';
-          element.swimlaneId = '';
           _id = element.copy(this.swimlaneId);
         } else if (this.isSwimlaneTemplateSearch) {
+          element.boardId = this.boardId;
           element.sort = Boards.findOne(this.boardId).swimlanes().count();
           element.type = 'swimlalne';
           _id = element.copy();
+        } else if (this.isBoardTemplateSearch) {
+          board = Boards.findOne(element.linkedId);
+          board.sort = Boards.find({archived: false}).count();
+          board.type = 'board';
+          delete board.slug;
+          delete board.members;
+          _id = board.copy();
         }
         Popup.close();
       },

+ 3 - 1
client/components/main/editor.js

@@ -36,7 +36,10 @@ import sanitizeXss from 'xss';
 const at = HTML.CharRef({html: '@', str: '@'});
 Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
   const view = this;
+  let content = Blaze.toHTML(view.templateContentBlock);
   const currentBoard = Boards.findOne(Session.get('currentBoard'));
+  if (!currentBoard)
+    return HTML.Raw(sanitizeXss(content));
   const knowedUsers = currentBoard.members.map((member) => {
     const u = Users.findOne(member.userId);
     if(u){
@@ -45,7 +48,6 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
     return member;
   });
   const mentionRegex = /\B@([\w.]*)/gi;
-  let content = Blaze.toHTML(view.templateContentBlock);
 
   let currentMention;
   while ((currentMention = mentionRegex.exec(content)) !== null) {

+ 36 - 0
models/boards.js

@@ -315,6 +315,21 @@ Boards.attachSchema(new SimpleSchema({
 
 
 Boards.helpers({
+  copy() {
+    const oldId = this._id;
+    delete this._id;
+    const _id = Boards.insert(this);
+
+    // Copy all swimlanes in board
+    Swimlanes.find({
+      boardId: oldId,
+      archived: false,
+    }).forEach((swimlane) => {
+      swimlane.type = 'swimlane';
+      swimlane.boardId = _id;
+      swimlane.copy(oldId);
+    });
+  },
   /**
    * Is supplied user authorized to view this board?
    */
@@ -463,6 +478,27 @@ Boards.helpers({
     return _id;
   },
 
+  searchBoards(term) {
+    check(term, Match.OneOf(String, null, undefined));
+
+    const query = { boardId: this._id };
+    query.type = 'cardType-linkedBoard';
+    query.archived = false;
+
+    const projection = { limit: 10, sort: { createdAt: -1 } };
+
+    if (term) {
+      const regex = new RegExp(term, 'i');
+
+      query.$or = [
+        { title: regex },
+        { description: regex },
+      ];
+    }
+
+    return Cards.find(query, projection);
+  },
+
   searchSwimlanes(term) {
     check(term, Match.OneOf(String, null, undefined));
 

+ 1 - 1
models/cardComments.js

@@ -69,7 +69,7 @@ CardComments.allow({
 CardComments.helpers({
   copy(newCardId) {
     this.cardId = newCardId;
-    this._id = null;
+    delete this._id;
     CardComments.insert(this);
   },
 

+ 1 - 1
models/cards.js

@@ -274,7 +274,7 @@ Cards.allow({
 Cards.helpers({
   copy() {
     const oldId = this._id;
-    this._id = null;
+    delete this._id;
     const _id = Cards.insert(this);
 
     // copy checklists

+ 5 - 1
models/lists.js

@@ -139,20 +139,24 @@ Lists.allow({
 Lists.helpers({
   copy(swimlaneId) {
     const oldId = this._id;
+    const oldSwimlaneId = this.swimlaneId || null;
     let _id = null;
     existingListWithSameName = Lists.findOne({
       boardId: this.boardId,
       title: this.title,
+      archived: false,
     });
     if (existingListWithSameName) {
       _id = existingListWithSameName._id;
     } else {
-      this._id = null;
+      delete this._id;
+      delete this.swimlaneId;
       _id = Lists.insert(this);
     }
 
     // Copy all cards in list
     Cards.find({
+      swimlaneId: oldSwimlaneId,
       listId: oldId,
       archived: false,
     }).forEach((card) => {

+ 12 - 7
models/swimlanes.js

@@ -101,18 +101,23 @@ Swimlanes.allow({
 });
 
 Swimlanes.helpers({
-  copy() {
+  copy(oldBoardId) {
     const oldId = this._id;
-    this._id = null;
+    delete this._id;
     const _id = Swimlanes.insert(this);
 
-    // Copy all lists in swimlane
-    Lists.find({
-      swimlaneId: oldId,
+    const query = {
+      swimlaneId: {$in: [oldId, '']},
       archived: false,
-    }).forEach((list) => {
+    };
+    if (oldBoardId) {
+      query.boardId = oldBoardId;
+    }
+
+    // Copy all lists in swimlane
+    Lists.find(query).forEach((list) => {
       list.type = 'list';
-      list.swimlaneId = '';
+      list.swimlaneId = oldId;
       list.boardId = this.boardId;
       list.copy(_id);
     });