Преглед изворни кода

Merge branch 'master' of https://github.com/mark-i-m/wekan into mark-i-m-master

Lauri Ojansivu пре 1 година
родитељ
комит
a2f479f4bd

+ 5 - 2
client/components/lists/list.css

@@ -7,8 +7,8 @@
   border-left: 1px solid #ccc;
   border-left: 1px solid #ccc;
   padding: 0;
   padding: 0;
   float: left;
   float: left;
-  min-width: 270px;
-  max-width: 270px;
+  min-width: 100px; /* TODO(mark-i-m): hardcoded? */
+  /*max-width: 270px;*/
   /* Reverted incomplete change list width: */
   /* Reverted incomplete change list width: */
   /* https://github.com/wekan/wekan/issues/4558 */
   /* https://github.com/wekan/wekan/issues/4558 */
   /* Orinal width: 270px. Changes not saved yet: */
   /* Orinal width: 270px. Changes not saved yet: */
@@ -179,6 +179,9 @@
 #js-wip-limit-edit div {
 #js-wip-limit-edit div {
   float: left;
   float: left;
 }
 }
+#js-list-width-edit .list-width-error {
+  display: none;
+}
 @media screen and (max-width: 800px) {
 @media screen and (max-width: 800px) {
   .mini-list {
   .mini-list {
     flex: 0 0 60px;
     flex: 0 0 60px;

+ 2 - 1
client/components/lists/list.jade

@@ -1,5 +1,6 @@
 template(name='list')
 template(name='list')
-  .list.js-list(id="js-list-{{_id}}")
+  .list.js-list(id="js-list-{{_id}}"
+                style="width:{{listWidth}}px;")
     +listHeader
     +listHeader
     +listBody
     +listBody
 
 

+ 6 - 0
client/components/lists/list.js

@@ -194,6 +194,12 @@ BlazeComponent.extendComponent({
       });
       });
     });
     });
   },
   },
+
+  listWidth() {
+    const user = Meteor.user();
+    const list = Template.currentData();
+    return user.getListWidth(list.boardId, list._id);
+  },
 }).register('list');
 }).register('list');
 
 
 Template.miniList.events({
 Template.miniList.events({

+ 18 - 0
client/components/lists/listHeader.jade

@@ -62,6 +62,11 @@ template(name="listActionPopup")
         i.fa.fa-arrow-down
         i.fa.fa-arrow-down
         | {{_ 'add-card-to-bottom-of-list'}}
         | {{_ 'add-card-to-bottom-of-list'}}
   hr
   hr
+  ul.pop-over-list
+    li
+      a.js-set-list-width
+        i.fa.fa-arrows-h
+        |  {{_ 'set-list-width'}}
   ul.pop-over-list
   ul.pop-over-list
     li
     li
       a.js-toggle-watch-list
       a.js-toggle-watch-list
@@ -156,6 +161,19 @@ template(name="wipLimitErrorPopup")
     p {{_ 'wipLimitErrorPopup-dialog-pt2'}}
     p {{_ 'wipLimitErrorPopup-dialog-pt2'}}
     button.full.js-back-view(type="submit") {{_ 'cancel'}}
     button.full.js-back-view(type="submit") {{_ 'cancel'}}
 
 
+template(name="setListWidthPopup")
+  #js-list-width-edit
+    label {{_ 'set-list-width-value'}}
+      p
+        input.list-width-value(type="number" value="{{ listWidthValue }}" min="100")
+        input.list-width-apply(type="submit" value="{{_ 'apply'}}")
+        input.list-width-error
+
+template(name="listWidthErrorPopup")
+  .list-width-invalid
+    p {{_ 'list-width-error-message'}}
+    button.full.js-back-view(type="submit") {{_ 'cancel'}}
+
 template(name="setListColorPopup")
 template(name="setListColorPopup")
   form.edit-label
   form.edit-label
     .palette-colors: each colors
     .palette-colors: each colors

+ 39 - 0
client/components/lists/listHeader.js

@@ -153,6 +153,7 @@ Template.listActionPopup.events({
     });
     });
     Popup.back();
     Popup.back();
   },
   },
+  'click .js-set-list-width': Popup.open('setListWidth'),
   'click .js-set-color-list': Popup.open('setListColor'),
   'click .js-set-color-list': Popup.open('setListColor'),
   'click .js-select-cards'() {
   'click .js-select-cards'() {
     const cardIds = this.allCards().map(card => card._id);
     const cardIds = this.allCards().map(card => card._id);
@@ -320,3 +321,41 @@ BlazeComponent.extendComponent({
     ];
     ];
   },
   },
 }).register('setListColorPopup');
 }).register('setListColorPopup');
+
+BlazeComponent.extendComponent({
+  applyListWidth() {
+    const list = Template.currentData();
+    const board = list.boardId;
+    const width = parseInt(
+      Template.instance()
+        .$('.list-width-value')
+        .val(),
+      10,
+    );
+
+    // FIXME(mark-i-m): where do we put constants?
+    if (width < 100 || !width) {
+      Template.instance()
+        .$('.list-width-error')
+        .click();
+    } else {
+      Meteor.call('applyListWidth', board, list._id, width);
+      Popup.back();
+    }
+  },
+
+  listWidthValue() {
+    const list = Template.currentData();
+    const board = list.boardId;
+    return Meteor.user().getListWidth(board, list._id);
+  },
+
+  events() {
+    return [
+      {
+        'click .list-width-apply': this.applyListWidth,
+        'click .list-width-error': Popup.open('listWidthError'),
+      },
+    ];
+  },
+}).register('setListWidthPopup');

+ 16 - 0
client/components/swimlanes/swimlaneHeader.jade

@@ -44,6 +44,9 @@ template(name="swimlaneActionPopup")
        li: a.js-set-swimlane-color
        li: a.js-set-swimlane-color
         i.fa.fa-paint-brush
         i.fa.fa-paint-brush
         | {{_ 'select-color'}}
         | {{_ 'select-color'}}
+       li: a.js-set-swimlane-height
+        i.fa.fa-arrows-v
+        |  {{_ 'set-swimlane-height'}}
     unless this.isTemplateContainer
     unless this.isTemplateContainer
       hr
       hr
       ul.pop-over-list
       ul.pop-over-list
@@ -82,6 +85,19 @@ template(name="setSwimlaneColorPopup")
     button.primary.confirm.js-submit {{_ 'save'}}
     button.primary.confirm.js-submit {{_ 'save'}}
     button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
     button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
 
 
+template(name="setSwimlaneHeightPopup")
+  #js-swimlane-height-edit
+    label {{_ 'set-swimlane-height-value'}}
+      p
+        input.swimlane-height-value(type="number" value="{{ swimlaneHeightValue }}" min="100")
+        input.swimlane-height-apply(type="submit" value="{{_ 'apply'}}")
+        input.swimlane-height-error
+
+template(name="swimlaneHeightErrorPopup")
+  .swimlane-height-invalid
+    p {{_ 'swimlane-height-error-message'}}
+    button.full.js-back-view(type="submit") {{_ 'cancel'}}
+
 template(name="swimlaneDeletePopup")
 template(name="swimlaneDeletePopup")
   p {{_ "swimlane-delete-pop"}}
   p {{_ "swimlane-delete-pop"}}
   button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
   button.js-confirm.negate.full(type="submit") {{_ 'delete'}}

+ 43 - 0
client/components/swimlanes/swimlaneHeader.js

@@ -37,6 +37,7 @@ Template.swimlaneFixedHeader.helpers({
 
 
 Template.swimlaneActionPopup.events({
 Template.swimlaneActionPopup.events({
   'click .js-set-swimlane-color': Popup.open('setSwimlaneColor'),
   'click .js-set-swimlane-color': Popup.open('setSwimlaneColor'),
+  'click .js-set-swimlane-height': Popup.open('setSwimlaneHeight'),
   'click .js-close-swimlane'(event) {
   'click .js-close-swimlane'(event) {
     event.preventDefault();
     event.preventDefault();
     this.archive();
     this.archive();
@@ -129,3 +130,45 @@ BlazeComponent.extendComponent({
     ];
     ];
   },
   },
 }).register('setSwimlaneColorPopup');
 }).register('setSwimlaneColorPopup');
+
+BlazeComponent.extendComponent({
+  onCreated() {
+    this.currentSwimlane = this.currentData();
+  },
+
+  applySwimlaneHeight() {
+    const swimlane = this.currentData();
+    const board = swimlane.boardId;
+    const height = parseInt(
+      Template.instance()
+        .$('.swimlane-height-value')
+        .val(),
+      10,
+    );
+
+    // FIXME(mark-i-m): where do we put constants?
+    if (height < 100 || !height) {
+      Template.instance()
+        .$('.swimlane-height-error')
+        .click();
+    } else {
+      Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
+      Popup.back();
+    }
+  },
+
+  swimlaneHeightValue() {
+    const swimlane = this.currentData();
+    const board = swimlane.boardId;
+    return Meteor.user().getSwimlaneHeight(board, swimlane._id);
+  },
+
+  events() {
+    return [
+      {
+        'click .swimlane-height-apply': this.applySwimlaneHeight,
+        'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
+      },
+    ];
+  },
+}).register('setSwimlaneHeightPopup');

+ 3 - 0
client/components/swimlanes/swimlanes.css

@@ -116,6 +116,9 @@
   left: 87vw;
   left: 87vw;
   font-size: 24px;
   font-size: 24px;
 }
 }
+#js-swimlane-height-edit .swimlane-height-error {
+  display: none;
+}
 .list-group {
 .list-group {
   height: 100%;
   height: 100%;
 }
 }

+ 2 - 1
client/components/swimlanes/swimlanes.jade

@@ -2,7 +2,8 @@ template(name="swimlane")
   .swimlane
   .swimlane
     +swimlaneHeader
     +swimlaneHeader
   unless collapseSwimlane
   unless collapseSwimlane
-    .swimlane.js-lists.js-swimlane(id="swimlane-{{_id}}")
+    .swimlane.js-lists.js-swimlane(id="swimlane-{{_id}}"
+                                   style="height:{{swimlaneHeight}}px;")
       if isMiniScreen
       if isMiniScreen
         if currentListIsInThisSwimlane _id
         if currentListIsInThisSwimlane _id
           +list(currentList)
           +list(currentList)

+ 6 - 0
client/components/swimlanes/swimlanes.js

@@ -223,6 +223,12 @@ BlazeComponent.extendComponent({
       },
       },
     ];
     ];
   },
   },
+
+  swimlaneHeight() {
+    const user = Meteor.user();
+    const swimlane = Template.currentData();
+    return user.getSwimlaneHeight(swimlane.boardId, swimlane._id);
+  },
 }).register('swimlane');
 }).register('swimlane');
 
 
 BlazeComponent.extendComponent({
 BlazeComponent.extendComponent({

+ 8 - 0
imports/i18n/data/en.i18n.json

@@ -85,6 +85,14 @@
   "add-card": "Add Card",
   "add-card": "Add Card",
   "add-card-to-top-of-list": "Add Card to Top of List",
   "add-card-to-top-of-list": "Add Card to Top of List",
   "add-card-to-bottom-of-list": "Add Card to Bottom of List",
   "add-card-to-bottom-of-list": "Add Card to Bottom of List",
+  "setListWidthPopup-title": "Set List Width",
+  "set-list-width": "Set List Width",
+  "set-list-width-value": "List Width (pixels)",
+  "list-width-error-message": "List width must be a positive integer >=100. TODO(mark-i-m): hard-coded constants",
+  "setSwimlaneHeightPopup-title": "Set Swimlane Height",
+  "set-swimlane-height": "Set Swimlane Height",
+  "set-swimlane-height-value": "Swimlane Height (pixels)",
+  "swimlane-height-error-message": "Swimlane height must be a positive integer >=100. TODO(mark-i-m): hard-coded constants",
   "add-swimlane": "Add Swimlane",
   "add-swimlane": "Add Swimlane",
   "add-subtask": "Add Subtask",
   "add-subtask": "Add Subtask",
   "add-checklist": "Add Checklist",
   "add-checklist": "Add Checklist",

+ 0 - 15
models/lists.js

@@ -80,21 +80,6 @@ Lists.attachSchema(
       // XXX We should probably provide a default
       // XXX We should probably provide a default
       optional: true,
       optional: true,
     },
     },
-    width: {
-      /**
-       * list width, default 270px
-       */
-      type: String,
-      defaultValue: '270px',
-      optional: true,
-    },
-    height: {
-      /**
-       * list height
-       */
-      type: String,
-      optional: true,
-    },
     updatedAt: {
     updatedAt: {
       /**
       /**
        * last update of the list
        * last update of the list

+ 84 - 0
models/users.js

@@ -422,6 +422,24 @@ Users.attachSchema(
       type: String,
       type: String,
       defaultValue: '',
       defaultValue: '',
     },
     },
+    'profile.listWidths': {
+      /**
+       * User-specified width of each list (or nothing if default).
+       * profile[boardId][listId] = width;
+       */
+      type: Object,
+      defaultValue: {},
+      blackbox: true,
+    },
+    'profile.swimlaneHeights': {
+      /**
+       * User-specified heights of each swimlane (or nothing if default).
+       * profile[boardId][swimlaneId] = height;
+       */
+      type: Object,
+      defaultValue: {},
+      blackbox: true,
+    },
     services: {
     services: {
       /**
       /**
        * services field of the user
        * services field of the user
@@ -758,6 +776,32 @@ Users.helpers({
     return this._getListSortBy()[1];
     return this._getListSortBy()[1];
   },
   },
 
 
+  getListWidths() {
+    const { listWidths = {} } = this.profile || {};
+    return listWidths;
+  },
+  getListWidth(boardId, listId) {
+    const listWidths = this.getListWidths();
+    if (listWidths[boardId] && listWidths[boardId][listId]) {
+      return listWidths[boardId][listId];
+    } else {
+      return 270; //TODO(mark-i-m): default?
+    }
+  },
+
+  getSwimlaneHeights() {
+    const { swimlaneHeights = {} } = this.profile || {};
+    return swimlaneHeights;
+  },
+  getSwimlaneHeight(boardId, listId) {
+    const swimlaneHeights = this.getSwimlaneHeights();
+    if (swimlaneHeights[boardId] && swimlaneHeights[boardId][listId]) {
+      return swimlaneHeights[boardId][listId];
+    } else {
+      return 270; //TODO(mark-i-m): default?
+    }
+  },
+
   /** returns all confirmed move and copy dialog field values
   /** returns all confirmed move and copy dialog field values
    * <li> the board, swimlane and list id is stored for each board
    * <li> the board, swimlane and list id is stored for each board
    */
    */
@@ -1135,6 +1179,32 @@ Users.mutations({
       },
       },
     };
     };
   },
   },
+
+  setListWidth(boardId, listId, width) {
+    let currentWidths = this.getListWidths();
+    if (!currentWidths[boardId]) {
+      currentWidths[boardId] = {};
+    }
+    currentWidths[boardId][listId] = width;
+    return {
+      $set: {
+        'profile.listWidths': currentWidths,
+      },
+    };
+  },
+
+  setSwimlaneHeight(boardId, swimlaneId, height) {
+    let currentHeights = this.getSwimlaneHeights();
+    if (!currentHeights[boardId]) {
+      currentHeights[boardId] = {};
+    }
+    currentHeights[boardId][swimlaneId] = height;
+    return {
+      $set: {
+        'profile.swimlaneHeights': currentHeights,
+      },
+    };
+  },
 });
 });
 
 
 Meteor.methods({
 Meteor.methods({
@@ -1178,6 +1248,20 @@ Meteor.methods({
     check(startDay, Number);
     check(startDay, Number);
     ReactiveCache.getCurrentUser().setStartDayOfWeek(startDay);
     ReactiveCache.getCurrentUser().setStartDayOfWeek(startDay);
   },
   },
+  applyListWidth(boardId, listId, width) {
+    check(boardId, String);
+    check(listId, String);
+    check(width, Number);
+    const user = Meteor.user();
+    user.setListWidth(boardId, listId, width);
+  },
+  applySwimlaneHeight(boardId, swimlaneId, height) {
+    check(boardId, String);
+    check(swimlaneId, String);
+    check(height, Number);
+    const user = Meteor.user();
+    user.setSwimlaneHeight(boardId, swimlaneId, height);
+  },
 });
 });
 
 
 if (Meteor.isServer) {
 if (Meteor.isServer) {