浏览代码

Merge pull request #3935 from syndimann/feature/boardwise-card-numbers

Feature: Consecutive boardwise card numbering
Lauri Ojansivu 4 年之前
父节点
当前提交
8bb33c53f0

+ 3 - 0
client/components/cards/cardDetails.jade

@@ -25,6 +25,9 @@ template(name="cardDetails")
         h2.card-details-title.js-card-title(
           class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
             +viewer
+              if currentBoard.allowsCardNumber
+                span.card-number
+                  | ##{getCardNumber}
               = getTitle
             if isWatching
               i.card-details-watch.fa.fa-eye

+ 6 - 0
client/components/cards/cardDetails.styl

@@ -114,6 +114,12 @@ avatar-radius = 50%
     background: darken(white, 7%)
     border-bottom: 1px solid darken(white, 14%)
 
+    .card-number {
+      color: darken(white, 30%);
+      display: inline-block;
+      margin-right: 5px;
+    }
+
     .close-card-details,
     .maximize-card-details,
     .minimize-card-details,

+ 3 - 0
client/components/cards/minicard.jade

@@ -37,6 +37,9 @@ template(name="minicard")
       if getArchived
         span.linked-icon.linked-archived.fa.fa-archive
       +viewer
+        if currentBoard.allowsCardNumber
+          span.card-number
+            | ##{getCardNumber}
         = getTitle
       if $eq 'subtext-with-full-path' currentBoard.presentParentTask
         .parent-subtext

+ 4 - 0
client/components/cards/minicard.styl

@@ -114,6 +114,10 @@
       font-size:20px;
       color: #ccc;
   .minicard-title
+    .card-number
+      color: darken(white, 30%);
+      display: inline-block;
+      margin-right: 5px;
     p:last-child
       margin-bottom: 0
     .viewer

+ 16 - 13
client/components/lists/listBody.js

@@ -81,7 +81,9 @@ BlazeComponent.extendComponent({
         Utils.boardView() === 'board-view-cal' ||
         !Utils.boardView()
       )
-        swimlaneId = board.getDefaultSwimline()._id;
+      swimlaneId = board.getDefaultSwimline()._id;
+
+      const nextCardNumber = board.getNextCardNumber();
 
       const _id = Cards.insert({
         title,
@@ -93,6 +95,7 @@ BlazeComponent.extendComponent({
         sort: sortIndex,
         swimlaneId,
         type: cardType,
+        cardNumber: nextCardNumber,
         linkedId,
       });
 
@@ -241,7 +244,7 @@ BlazeComponent.extendComponent({
       Boards.findOne(currentBoardId)
         .customFields()
         .fetch(),
-      function(field) {
+      function (field) {
         if (field.automaticallyOnCard || field.alwaysOnCard)
           arr.push({ _id: field._id, value: null });
       },
@@ -750,17 +753,17 @@ BlazeComponent.extendComponent({
 
   checkIdleTime() {
     return window.requestIdleCallback ||
-    function(handler) {
-      const startTime = Date.now();
-      return setTimeout(function() {
-        handler({
-          didTimeout: false,
-          timeRemaining() {
-            return Math.max(0, 50.0 - (Date.now() - startTime));
-          },
-        });
-      }, 1);
-    };
+      function (handler) {
+        const startTime = Date.now();
+        return setTimeout(function () {
+          handler({
+            didTimeout: false,
+            timeRemaining() {
+              return Math.max(0, 50.0 - (Date.now() - startTime));
+            },
+          });
+        }, 1);
+      };
   }
 
   updateList() {

+ 7 - 0
client/components/sidebar/sidebar.jade

@@ -189,6 +189,13 @@ template(name="boardCardSettingsPopup")
         span
           i.fa.fa-tags
           | {{_ 'labels'}}
+    div.check-div
+      a.flex.js-field-has-card-number(class="{{#if allowsCardNumber}}is-checked{{/if}}")
+        .materialCheckBox(class="{{#if allowsCardNumber}}is-checked{{/if}}")
+        span
+          i.fa.fa-hashtag
+          | {{_ 'card'}}
+          | {{_ 'number'}}
     div.check-div
       a.flex.js-field-has-description-title(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
         .materialCheckBox(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")

+ 20 - 0
client/components/sidebar/sidebar.js

@@ -776,6 +776,10 @@ BlazeComponent.extendComponent({
     return this.currentBoard.allowsComments;
   },
 
+  allowsCardNumber() {
+    return this.currentBoard.allowsCardNumber;
+  },
+
   allowsDescriptionTitle() {
     return this.currentBoard.allowsDescriptionTitle;
   },
@@ -1019,6 +1023,22 @@ BlazeComponent.extendComponent({
             this.currentBoard.allowsDescriptionTitle,
           );
         },
+        'click .js-field-has-card-number'(evt) {
+          evt.preventDefault();
+          this.currentBoard.allowsCardNumber = !this.currentBoard
+            .allowsCardNumber;
+          this.currentBoard.setAllowsCardNumber(
+            this.currentBoard.allowsCardNumber,
+          );
+          $(`.js-field-has-card-number ${MCB}`).toggleClass(
+            CKCLS,
+            this.currentBoard.allowsCardNumber,
+          );
+          $('.js-field-has-card-number').toggleClass(
+            CKCLS,
+            this.currentBoard.allowsCardNumber,
+          );
+        },
         'click .js-field-has-description-text'(evt) {
           evt.preventDefault();
           this.currentBoard.allowsDescriptionText = !this.currentBoard

+ 17 - 0
models/boards.js

@@ -375,6 +375,14 @@ Boards.attachSchema(
       defaultValue: true,
     },
 
+    allowsCardNumber: {
+      /**
+       * Does the board allows card numbers?
+       */
+      type: Boolean,
+      defaultValue: false,
+    },
+
     allowsActivities: {
       /**
        * Does the board allows comments?
@@ -1056,6 +1064,11 @@ Boards.helpers({
     return result;
   },
 
+  getNextCardNumber() {
+    const boardCards = Cards.find({ boardId: this._id }).fetch();
+    return boardCards.length + 1;
+  },
+
   cardsDueInBetween(start, end) {
     return Cards.find({
       boardId: this._id,
@@ -1285,6 +1298,10 @@ Boards.mutations({
     return { $set: { allowsDescriptionTitle } };
   },
 
+  setAllowsCardNumber(allowsCardNumber) {
+    return { $set: { allowsCardNumber } };
+  },
+
   setAllowsDescriptionText(allowsDescriptionText) {
     return { $set: { allowsDescriptionText } };
   },

+ 17 - 0
models/cards.js

@@ -470,6 +470,16 @@ Cards.attachSchema(
       optional: true,
       defaultValue: [],
     },
+    cardNumber: {
+      /**
+       * A boardwise sequentially increasing number that is assigned
+       * to every newly created card
+       */
+      type: Number,
+      decimal: true,
+      optional: true,
+      defaultValue: 0,
+    },
   }),
 );
 
@@ -1647,6 +1657,10 @@ Cards.helpers({
     }
   },
 
+  getCardNumber() {
+    return this.cardNumber;
+  },
+
   getBoardTitle() {
     if (this.isLinkedCard()) {
       const card = Cards.findOne({ _id: this.linkedId });
@@ -3207,6 +3221,8 @@ if (Meteor.isServer) {
     Authentication.checkAdminOrCondition(req.userId, addPermission);
     const paramListId = req.params.listId;
     const paramParentId = req.params.parentId;
+
+    const nextCardNumber = board.getNextCardNumber();
     const currentCards = Cards.find(
       {
         listId: paramListId,
@@ -3229,6 +3245,7 @@ if (Meteor.isServer) {
         userId: req.body.authorId,
         swimlaneId: req.body.swimlaneId,
         sort: currentCards.count(),
+        cardNumber: nextCardNumber,
         members,
         assignees,
       });

+ 39 - 0
server/migrations.js

@@ -1061,3 +1061,42 @@ Migrations.add('add-hide-logo-by-default', () => {
     noValidateMulti,
   );
 });
+
+Migrations.add('add-card-number-allowed', () => {
+  Boards.update(
+    {
+      allowsCardNumber: {
+        $exists: false,
+      },
+    },
+    {
+      $set: {
+        allowsCardNumber: false,
+      },
+    },
+    noValidateMulti,
+  );
+});
+
+Migrations.add('assign-boardwise-card-numbers', () => {
+  Boards.find().forEach(board => {
+    let nextCardNumber = board.getNextCardNumber();
+    Cards.find(
+      {
+        boardId: board._id,
+        cardNumber: {
+          $exists: false
+        }
+      },
+      {
+        sort: { createdAt: 1 }
+      }
+    ).forEach(card => {
+      Cards.update(
+        card._id,
+        { $set: { cardNumber: nextCardNumber } },
+        noValidate);
+      nextCardNumber++;
+    });
+  })
+});