|  | @@ -422,6 +422,24 @@ Users.attachSchema(
 | 
	
		
			
				|  |  |        type: String,
 | 
	
		
			
				|  |  |        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 field of the user
 | 
	
	
		
			
				|  | @@ -758,6 +776,32 @@ Users.helpers({
 | 
	
		
			
				|  |  |      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
 | 
	
		
			
				|  |  |     * <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({
 | 
	
	
		
			
				|  | @@ -1178,6 +1248,20 @@ Meteor.methods({
 | 
	
		
			
				|  |  |      check(startDay, Number);
 | 
	
		
			
				|  |  |      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) {
 |