UNPKG

trello-sprinter

Version:

Provides summarizations of sprint activity in a Trello project

1,443 lines (1,174 loc) 167 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["TrelloSprinter"] = factory(); else root["TrelloSprinter"] = factory(); })(self, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./index.js": /*!******************!*\ !*** ./index.js ***! \******************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "TrelloSprinter": () => (/* reexport safe */ _src_TrelloSprinter__WEBPACK_IMPORTED_MODULE_1__.TrelloSprinter), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _trello_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./trello.scss */ "./trello.scss"); /* harmony import */ var _src_TrelloSprinter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/TrelloSprinter */ "./src/TrelloSprinter.js"); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_src_TrelloSprinter__WEBPACK_IMPORTED_MODULE_1__.TrelloSprinter); /***/ }), /***/ "./src/Board.js": /*!**********************!*\ !*** ./src/Board.js ***! \**********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Board": () => (/* binding */ Board) /* harmony export */ }); /* harmony import */ var _Member__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Member */ "./src/Member.js"); /* harmony import */ var _List__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./List */ "./src/List.js"); /* harmony import */ var _Card__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Card */ "./src/Card.js"); /* harmony import */ var _Update__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Update */ "./src/Update.js"); /* harmony import */ var _Comment__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Comment */ "./src/Comment.js"); /* * Representation of a Trello Board */ var Board = function Board(data, options) { this.data = data; this.id = data.id; this.name = data.name; this.lists = []; this.members = {}; this.options = options; this.find_card = function (id) { for (var i = 0; i < this.lists.length; i++) { var card = this.lists[i].find_card(id); if (card !== null) { return card; } } return null; }; this.add_member = function (member) { this.members[member.id] = member; }; }; Board.fetch = function (trello, name, options, msg, success, failure) { msg.innerText = 'Fetching board ' + name; /// Keeps track of how many open async calls there are right now var active = 0; // Will be set to point to a new Board object var board = null; async_start(); trello.get("/member/me/boards?fields=all", function (data) { for (var i = 0; i < data.length; i++) { var boardData = data[i]; if (boardData.name.toLowerCase() === name.toLowerCase()) { // We have found the board (if not closed) if (!boardData.closed) { // Create the board object board = new Board(boardData, options); // Fetch the membership fetch_membership(board); // Fetch the lists for the board fetch_lists(board); break; } } } if (board === null) { failure("Unable to find Trello board " + name); return; } async_end(); }, function (data) { failure("Unable to fetch Trello boards"); }, msg); /** * Fetch the membership of the board. * @param board Board to fetch for */ function fetch_membership(board) { async_start(); trello.get("/board/" + board.id + "/members?fields=all", function (data) { data.forEach(function (memberData) { var member = new _Member__WEBPACK_IMPORTED_MODULE_0__.Member(board, memberData); board.add_member(member); }); async_end(); }, function (data) { failure("Unable to fetch Trello membership"); }, msg); } function fetch_lists(board) { msg.innerText = "Fetching lists for " + name; async_start(); trello.get("/boards/" + board.id + "/lists?filter=open", function (data) { data.forEach(function (listData) { if (!listData.closed) { var list = new _List__WEBPACK_IMPORTED_MODULE_1__.List(board, listData); board.lists.push(list); } }); fetch_cards(board); async_end(); }, function (data) { failure("Unable to fetch Trello lists"); }, msg); } /** * Fetch all cards as a single batch operation. * @param board Board we are fetching for */ function fetch_cards(board) { msg.innerText = "Fetching cards"; // Collect up all URLs for all of the lists var urls = ''; for (var i = 0; i < board.lists.length; i++) { var list = board.lists[i]; if (urls.length > 0) { urls += ','; } urls += "/lists/" + list.id + "/cards/open"; } // Get get it async_start(); trello.get("/batch?urls=" + urls, function (data) { var _loop = function _loop(_i) { var list = board.lists[_i]; var cardsData = data[_i][200]; cardsData.forEach(function (cardData) { if (!cardData.closed) { var card = new _Card__WEBPACK_IMPORTED_MODULE_2__.Card(board, list, cardData); if (options.after !== null) { if (card.created.getTime() / 1000 > options.after) { list.add_card(card); } } else { list.add_card(card); } } }); }; // Loop over the result for each provided URL for (var _i = 0; _i < data.length && _i < board.lists.length; _i++) { _loop(_i); } fetch_actions(board); async_end(); }, function (data) { failure("Unable to fetch Trello cards"); }, msg); } function fetch_actions(board) { async_start(); trello.get("/board/" + board.id + "/actions?filter=commentCard,updateCard:idList&limit=1000", function (data) { data.forEach(function (action) { if (!action.closed) { if (action.type === "commentCard") { var card = board.find_card(action.data.card.id); if (card !== null) { var comment = new _Comment__WEBPACK_IMPORTED_MODULE_4__.Comment(board, card, action); card.comments.push(comment); } //console.log(action); } else if (action.type === 'updateCard') { var _card = board.find_card(action.data.card.id); if (_card !== null) { var update = new _Update__WEBPACK_IMPORTED_MODULE_3__.Update(board, _card, action); _card.updates.push(update); } //console.log(action); } } }); board.lists.forEach(function (list) { list.cards.forEach(function (card) { card.sort_updates(); }); }); async_end(); }, function (data) { failure("Unable to fetch Trello card information"); }, msg); } function async_start() { active++; } function async_end() { active--; if (active === 0) { success(board); } } }; Board.prototype.find_list = function (name) { name = name.toLowerCase(); for (var i = 0; i < this.lists.length; i++) { var list = this.lists[i]; if (list.name.toLowerCase() === name) { return list; } } return null; }; /***/ }), /***/ "./src/BoardView.js": /*!**************************!*\ !*** ./src/BoardView.js ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "BoardView": () => (/* binding */ BoardView) /* harmony export */ }); /* harmony import */ var _DataView__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./DataView */ "./src/DataView.js"); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Util */ "./src/Util.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * @file * Standard Trello board view */ var BoardView = function BoardView(div, board) { _DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.call(this); this.present = function () { var view = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-view'); div.appendChild(view); var _iterator = _createForOfIteratorHelper(board.lists), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var list = _step.value; presentList(view, list); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } }; var presentList = function presentList(view, list) { var header = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('h3', 'trello-plus'); header.innerText = list.name; view.appendChild(header); var expander = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-expand'); expander.style.display = 'none'; view.appendChild(expander); header.addEventListener('click', function (event) { if (expander.style.display === 'none') { expander.style.display = 'block'; _Util__WEBPACK_IMPORTED_MODULE_1__.Util.removeClass(header, 'trello-plus'); _Util__WEBPACK_IMPORTED_MODULE_1__.Util.addClass(header, 'trello-minus'); } else { expander.style.display = 'none'; _Util__WEBPACK_IMPORTED_MODULE_1__.Util.removeClass(header, 'trello-minus'); _Util__WEBPACK_IMPORTED_MODULE_1__.Util.addClass(header, 'trello-plus'); } }); var count = list.count_members(); var members = '<em>Cards:</em>[' + list.cards.length + '] '; for (var c in count) { if (count.hasOwnProperty(c)) { members += count[c].member.name + ':[' + count[c].cnt + ']&nbsp;&nbsp;'; } } var countEl = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('p', 'trello-count'); expander.appendChild(countEl); countEl.innerHTML = members; var _iterator2 = _createForOfIteratorHelper(list.cards), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var card = _step2.value; presentCard(expander, card); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } }; var presentCard = function presentCard(div, card) { // // Heading // var date = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.formatDatetime(card.created); var cardDiv = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-card'); div.appendChild(cardDiv); cardDiv.innerHTML = "<h4><span class=\"trello-date\">".concat(date, "</span>").concat(card.name, "</h4>"); // // Members // var members = ''; var _iterator3 = _createForOfIteratorHelper(card.members), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var id = _step3.value; var member = card.board.members[id]; if (members.length > 0) { members += ' / '; } members += '<span>' + member.name + '</span>'; } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } var membersP = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('p', 'trello-card-members'); cardDiv.appendChild(membersP); membersP.innerHTML = members; // // Description // var desc = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-description'); cardDiv.appendChild(desc); desc.innerHTML = card.desc; presentComments(cardDiv, card); presentUpdates(cardDiv, card); }; this.presentCard = presentCard; var presentComments = function presentComments(div, card) { if (card.comments.length === 0) { return; } var commentDiv = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-comments'); div.appendChild(commentDiv); var _iterator4 = _createForOfIteratorHelper(card.comments), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var comment = _step4.value; var member = card.board.members[comment.member]; var memberName = member !== undefined ? member.name : "undefined"; var date = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.formatDatetime(comment.date); var h5 = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('h5'); commentDiv.appendChild(h5); h5.innerHTML = "<span class=\"trello-date\">".concat(date, "</span>").concat(memberName); var textDiv = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div'); commentDiv.appendChild(textDiv); textDiv.innerHTML = comment.text; } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } }; var presentUpdates = function presentUpdates(div, card) { if (card.updates.length === 0) { return; } var updateDiv = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.createElement('div', 'trello-updates'); div.appendChild(updateDiv); var _iterator5 = _createForOfIteratorHelper(card.updates), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { var update = _step5.value; var member = card.board.members[update.member]; var memberName = member !== undefined ? member.name : "undefined"; var date = _Util__WEBPACK_IMPORTED_MODULE_1__.Util.formatDatetime(update.date); var p = document.createElement('p'); updateDiv.appendChild(p); p.innerHTML = '<span class="date">' + date + '</span> ' + memberName + ' moved from <span class="list">' + update.listBefore + '</span> to <span class="list">' + update.listAfter + '</span>'; } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } }; }; /// @cond BoardView.prototype = Object.create(_DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.prototype); BoardView.prototype.constructor = BoardView; /// @endcond /***/ }), /***/ "./src/Card.js": /*!*********************!*\ !*** ./src/Card.js ***! \*********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Card": () => (/* binding */ Card) /* harmony export */ }); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Util */ "./src/Util.js"); /** * @file * Representation of a Trello list in a board */ var Card = function Card(board, list, data) { var that = this; this.board = board; this.list = list; this.id = data.id; this.name = _Util__WEBPACK_IMPORTED_MODULE_0__.Util.strip_tags(data.name); this.data = data; this.desc = '<p>' + _Util__WEBPACK_IMPORTED_MODULE_0__.Util.strip_tags(data.desc).replace(/\n/gm, '<p>') + '</p>'; this.created = new Date(parseInt(data.id.substr(0, 8), 16) * 1000); this.members = []; data.idMembers.forEach(function (id) { that.members.push(id); }); this.comments = []; this.updates = []; }; Card.prototype.sort_updates = function () { this.updates.sort(function (a, b) { if (a.date < b.date) { return -1; } else if (a.date == b.date) { return 0; } else { return 1; } }); }; /** * Determine the last time this card was moved. * This is used to determine when a completed card was * moved to Completed. */ Card.prototype.final_time = function () { if (this.updates.length > 0) { return this.updates[this.updates.length - 1].date; } return this.created; }; /** * Count members from a collection of cards. * @param board Board object * @param list array of Card objects * @returns object with id as property to object {cnt: ?, member: ?} */ Card.count_members = function (board, list) { var count = {}; list.forEach(function (card) { card.members.forEach(function (id) { var member = board.members[id]; if (count.hasOwnProperty(member.id)) { count[member.id].cnt++; } else { count[member.id] = { cnt: 1, member: member }; } }); }); return count; }; /***/ }), /***/ "./src/Comment.js": /*!************************!*\ !*** ./src/Comment.js ***! \************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Comment": () => (/* binding */ Comment) /* harmony export */ }); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Util */ "./src/Util.js"); /** * @file * Representation of a Trello comment on a card */ /** Array ( [id] => 57eec1ca22684646b1193abd [idMemberCreator] => 57ec1bdafeedcbbc73d600d1 [data] => Array ( [list] => Array ( [name] => Design [id] => 57e920a2b34518203fd5f319 ) [board] => Array ( [shortLink] => i9eXE4yJ [name] => Project 1 Team: Arbo [id] => 57e9204ac3f323f1785d7be4 ) [card] => Array ( [shortLink] => Fggvd4nX [idShort] => 21 [name] => Visual Paradigm Class Design [id] => 57eec0776fd005f7b81c8239 ) [text] => Visual Paradigm Class Design ) [type] => commentCard [date] => 2016-09-30T19:49:30.974Z [memberCreator] => Array ( [id] => 57ec1bdafeedcbbc73d600d1 [avatarHash] => [fullName] => Brittany Galliers [initials] => BG [username] => brittanygalliers1 ) * @param board * @param card * @param data * @constructor */ var Comment = function Comment(board, card, data) { this.board = board; this.card = card; this.member = data.idMemberCreator; this.text = '<p>' + _Util__WEBPACK_IMPORTED_MODULE_0__.Util.strip_tags(data.data.text).replace(/\n/gm, '<p>') + '</p>'; this.data = data; this.date = new Date(Date.parse(data.date)); }; /***/ }), /***/ "./src/DataView.js": /*!*************************!*\ !*** ./src/DataView.js ***! \*************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataView": () => (/* binding */ DataView) /* harmony export */ }); /* * Base object for views of Trello data. */ var DataView = function DataView() {}; DataView.prototype.present = function (div, board) {}; /***/ }), /***/ "./src/DisconnectedView.js": /*!*********************************!*\ !*** ./src/DisconnectedView.js ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DisconnectedView": () => (/* binding */ DisconnectedView) /* harmony export */ }); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Util */ "./src/Util.js"); var DisconnectedView = function DisconnectedView(element, trello, options) { // Ensure empty element.innerHTML = ''; var div = document.createElement('div'); element.appendChild(div); _Util__WEBPACK_IMPORTED_MODULE_0__.Util.addClass(div, 'trello-sprinter'); var p = document.createElement('p'); div.appendChild(p); _Util__WEBPACK_IMPORTED_MODULE_0__.Util.addClass(p, 'center'); var button = document.createElement('button'); p.appendChild(button); button.innerText = 'Connect to Trello'; button.addEventListener('click', function (event) { event.preventDefault(); trello.authorize(); }); }; /***/ }), /***/ "./src/List.js": /*!*********************!*\ !*** ./src/List.js ***! \*********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "List": () => (/* binding */ List) /* harmony export */ }); /* harmony import */ var _Card__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Card */ "./src/Card.js"); /** * @file * Representation of a Trello list in a board */ var List = function List(board, data) { this.board = board; this.id = data.id; this.name = data.name; this.data = data; this.cards = []; this.cards_by_id = {}; }; List.prototype.add_card = function (card) { this.cards.push(card); this.cards_by_id[card.id] = card; }; List.prototype.find_card = function (id) { if (this.cards_by_id.hasOwnProperty(id)) { return this.cards_by_id[id]; } return null; }; List.prototype.count_members = function () { return _Card__WEBPACK_IMPORTED_MODULE_0__.Card.count_members(this.board, this.cards); }; /***/ }), /***/ "./src/MainView.js": /*!*************************!*\ !*** ./src/MainView.js ***! \*************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MainView": () => (/* binding */ MainView) /* harmony export */ }); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Util */ "./src/Util.js"); /* harmony import */ var _Board__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Board */ "./src/Board.js"); /* harmony import */ var _BoardView__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BoardView */ "./src/BoardView.js"); /* harmony import */ var _Sprints_SprintView__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Sprints/SprintView */ "./src/Sprints/SprintView.js"); /* harmony import */ var _Sprints_SprintTableView__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Sprints/SprintTableView */ "./src/Sprints/SprintTableView.js"); /* harmony import */ var _DisconnectedView__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./DisconnectedView */ "./src/DisconnectedView.js"); var MainView = function MainView(element, trello, options) { // Ensure empty element.innerHTML = ''; var div = document.createElement('div'); element.appendChild(div); _Util__WEBPACK_IMPORTED_MODULE_0__.Util.addClass(div, 'trello-sprinter'); var p = document.createElement('p'); div.appendChild(p); _Util__WEBPACK_IMPORTED_MODULE_0__.Util.addClass(p, 'center'); var button = document.createElement('button'); p.appendChild(button); button.innerText = 'Disconnect'; button.addEventListener('click', function (event) { event.preventDefault(); trello.disconnect(); new _DisconnectedView__WEBPACK_IMPORTED_MODULE_5__.DisconnectedView(element, trello, options); }); var pStatus = _Util__WEBPACK_IMPORTED_MODULE_0__.Util.createElement('p', 'trello-status'); pStatus.innerText = 'Connecting to Trello...'; div.appendChild(pStatus); var pMsg = _Util__WEBPACK_IMPORTED_MODULE_0__.Util.createElement('p', 'trello-msg'); div.appendChild(pMsg); _Board__WEBPACK_IMPORTED_MODULE_1__.Board.fetch(trello, options.board, options, pMsg, function (board) { // Success pStatus.innerText = 'Trello Board: ' + board.name; pMsg.parentNode.removeChild(pMsg); for (var view in options.views) { switch (view) { case 'board': var boardView = new _BoardView__WEBPACK_IMPORTED_MODULE_2__.BoardView(div, board); boardView.present(); break; case 'sprint': var sprintView = new _Sprints_SprintView__WEBPACK_IMPORTED_MODULE_3__.SprintView(div, board, options.views.sprint); sprintView.present(); break; case 'sprintTable': var sprintTableView = new _Sprints_SprintTableView__WEBPACK_IMPORTED_MODULE_4__.SprintTableView(div, board, options.views.sprintTable); sprintTableView.present(); break; } } }, function (msg) { // Failure pMsg.parentNode.removeChild(pMsg); pStatus.innerText = msg; }); //trello.fetch(); }; /***/ }), /***/ "./src/Member.js": /*!***********************!*\ !*** ./src/Member.js ***! \***********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Member": () => (/* binding */ Member) /* harmony export */ }); /* * Representation of a Trello member in a board */ var Member = function Member(board, data) { this.board = board; this.id = data.id; this.name = data.fullName; this.data = data; }; /***/ }), /***/ "./src/Sprints/Sprint.js": /*!*******************************!*\ !*** ./src/Sprints/Sprint.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Sprint": () => (/* binding */ Sprint) /* harmony export */ }); /* * Represents a single sprint in the sprints analysis */ var Sprint = function Sprint(sprints, start, end) { this.sprints = sprints; this.start_meeting = start; this.end_meeting = end; this.completed = []; }; Sprint.prototype.end_time = function () { return new Date(this.end_meeting.created.getTime() + this.sprints.sprint_time_slop * 1000); }; /***/ }), /***/ "./src/Sprints/SprintMember.js": /*!*************************************!*\ !*** ./src/Sprints/SprintMember.js ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SprintMember": () => (/* binding */ SprintMember) /* harmony export */ }); /** * @file * Team member statistics for a sprint */ var SprintMember = function SprintMember(sprints, member) { this.member = member; this.sprints = sprints; this.meetings_count = 0; this.meetings_attended = 0; this.completed_count = 0; this.completed_total = 0; this.reviews_count = 0; this.reviews_total = 0; }; SprintMember.prototype.meetings_percentage = function () { if (this.meetings_count <= this.sprints.meetings_slop) { return '(insufficient meetings)'; } var per = this.meetings_attended / (this.meetings_count - this.sprints.meetings_slop); if (per > 1) { per = 1; } return per.toFixed(2); }; SprintMember.prototype.completed_factor = function (teamSize) { if (this.completed_total === 0) { return 0; } var factor = this.completed_count / (this.completed_total / teamSize * this.sprints.completed_factor); if (factor > 1) { factor = 1; } return factor.toFixed(2); }; SprintMember.prototype.reviewing_factor = function (teamSize) { if (this.reviews_total === 0) { return 0; } var factor = this.reviews_count / (this.reviews_total / teamSize * this.sprints.reviewing_factor); if (factor > 1) { factor = 1; } return factor.toFixed(2); }; /***/ }), /***/ "./src/Sprints/SprintTableView.js": /*!****************************************!*\ !*** ./src/Sprints/SprintTableView.js ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SprintTableView": () => (/* binding */ SprintTableView) /* harmony export */ }); /* harmony import */ var _DataView__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../DataView */ "./src/DataView.js"); /* harmony import */ var _Sprints__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Sprints */ "./src/Sprints/Sprints.js"); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Util */ "./src/Util.js"); /* harmony import */ var _Card__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Card */ "./src/Card.js"); /* harmony import */ var _BoardView__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../BoardView */ "./src/BoardView.js"); /* * Trello board view that displays sprint result in a table. */ var SprintTableView = function SprintTableView(div, board, options) { _DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.call(this); var addHeadings = true; if (options.addHeadings !== undefined) { addHeadings = options.addHeadings; } this.present = function () { var view = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-sprint-table'); div.appendChild(view); var table = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('table'); view.appendChild(table); if (options["class"] !== undefined) { _Util__WEBPACK_IMPORTED_MODULE_2__.Util.addClass(table, options["class"]); } // // Create the sprint analysis // var sprints = new _Sprints__WEBPACK_IMPORTED_MODULE_1__.Sprints(board); var teamSize = sprints.num_members(); if (addHeadings) { tableHeading(table, board, sprints); } var rowHTML = ''; function item(data) { rowHTML += '<td>' + data + '</td>'; } for (var id in sprints.members) { if (sprints.members.hasOwnProperty(id)) { var member = sprints.members[id]; var id = member.member.id; rowHTML = ''; // Our statistics item(board.name); item(teamSize); item(member.member.name); item(member.meetings_attended); item(member.meetings_count); item(member.meetings_percentage()); item(member.completed_count); item(member.completed_total); item(member.completed_factor(teamSize)); item(member.reviews_count); item(member.reviews_total); item(member.reviewing_factor(teamSize)); item(sprints.sprints.length); sprints.sprints.forEach(function (sprint) { var cnt = 0; sprint.completed.forEach(function (card) { if (card.members.length == 1 && card.members[0] == id) { cnt++; } }); item(cnt); item(sprint.completed.length); }); if (!isNaN(addHeadings)) { for (var i = sprints.sprints.length; i < addHeadings; i++) { item("&nbsp;"); item("&nbsp;"); } } var tr = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('tr'); tr.innerHTML = rowHTML; table.appendChild(tr); } } }; var tableHeading = function tableHeading(table, board, sprints) { var tr = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('tr'); table.appendChild(tr); if (options.tr1class !== undefined) { _Util__WEBPACK_IMPORTED_MODULE_2__.Util.addClass(tr, options.tr1class); } var rowHTML = ''; function item(data) { rowHTML += '<th><div>' + data + '</div></th>'; } item("Team"); item("#"); item("Member"); item("Attended"); item("Total"); item("%"); item("Completed"); item("Total"); item("%"); item("Reviews"); item("Total"); item("%"); item("Sprints"); if (addHeadings === true) { for (var i = 1; i <= sprints.sprints.length; i++) { item(i); item("#"); } } else { for (var i = 1; i <= addHeadings; i++) { item(i); item("#"); } } tr.innerHTML = rowHTML; }; }; /// @cond SprintTableView.prototype = Object.create(_DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.prototype); SprintTableView.prototype.constructor = SprintTableView; /// @endcond SprintTableView.prototype.table_headings = function (board, sprints) {}; /***/ }), /***/ "./src/Sprints/SprintView.js": /*!***********************************!*\ !*** ./src/Sprints/SprintView.js ***! \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SprintView": () => (/* binding */ SprintView) /* harmony export */ }); /* harmony import */ var _DataView__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../DataView */ "./src/DataView.js"); /* harmony import */ var _Sprints__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Sprints */ "./src/Sprints/Sprints.js"); /* harmony import */ var _Util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Util */ "./src/Util.js"); /* harmony import */ var _Card__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Card */ "./src/Card.js"); /* harmony import */ var _BoardView__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../BoardView */ "./src/BoardView.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /** * @file * Trello board view that displays sprint results */ var SprintView = function SprintView(div, board) { _DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.call(this); // This uses BoardView to draw what it knows how to draw var board_view = new _BoardView__WEBPACK_IMPORTED_MODULE_4__.BoardView(div, board); this.present = function () { // // Create the sprint analysis // var sprints = new _Sprints__WEBPACK_IMPORTED_MODULE_1__.Sprints(board); var view = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-sprints'); div.appendChild(view); var h2 = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('h2'); h2.innerText = 'Sprints Analysis'; view.appendChild(h2); present_errors(view, sprints); present_warnings(view, sprints); if (sprints.errors.length > 0) { return; } present_sprints(view, sprints); present_members(view, sprints); }; var present_errors = function present_errors(div, sprints) { if (sprints.errors.length === 0) { return; } var errors = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-errors'); div.appendChild(errors); errors.innerHTML = '<h3>Errors</h3>'; var _iterator = _createForOfIteratorHelper(sprints.errors), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var error = _step.value; var p = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('p'); errors.appendChild(p); p.innerHTML = '<span class="trello-code">' + error.code + ':</span> ' + error.msg; } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } }; var present_warnings = function present_warnings(div, sprints) { if (sprints.warnings.length === 0) { return; } var warnings = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-warnings'); div.appendChild(warnings); warnings.innerHTML = '<h3>Warnings</h3>'; var _iterator2 = _createForOfIteratorHelper(sprints.warnings), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var warning = _step2.value; var p = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('p'); warnings.appendChild(p); p.innerHTML = '<span class="trello-code">' + warning.code + ':</span> ' + warning.msg; } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } }; var present_sprints = function present_sprints(div, sprints) { var view = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-view'); div.appendChild(view); for (var s = 1; s <= sprints.sprints.length; s++) { var sprint = sprints.sprints[s - 1]; present_sprint(view, sprints, s, sprint); } }; var present_sprint = function present_sprint(div, sprints, num, sprint) { var fmDate = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.formatDatetime(sprint.start_meeting.created); var toDate = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.formatDatetime(sprint.end_meeting.created); var completed = sprint.completed.length; // // Member counts for completed // var counts = _Card__WEBPACK_IMPORTED_MODULE_3__.Card.count_members(sprints.board, sprint.completed); var totalCompleted = 0; var _iterator3 = _createForOfIteratorHelper(sprints.sprints), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _sprint = _step3.value; totalCompleted += _sprint.completed.length; } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } var completionFactor = 0.00; if (totalCompleted > 0) { completionFactor = completed / (totalCompleted / sprints.sprints.length * 0.8); if (completionFactor > 1) { completionFactor = 1; } } completionFactor = completionFactor.toFixed(2); var header = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('h3', 'trello-plus'); div.appendChild(header); header.innerHTML = '<span class="date">' + completed + ' tasks ' + completionFactor + ' / ' + fmDate + ' to ' + toDate + '</span>Sprint: ' + num; var expander = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-expand'); expander.style.display = 'none'; div.appendChild(expander); header.addEventListener('click', function (event) { if (expander.style.display === 'none') { expander.style.display = 'block'; _Util__WEBPACK_IMPORTED_MODULE_2__.Util.removeClass(header, 'trello-plus'); _Util__WEBPACK_IMPORTED_MODULE_2__.Util.addClass(header, 'trello-minus'); } else { expander.style.display = 'none'; _Util__WEBPACK_IMPORTED_MODULE_2__.Util.removeClass(header, 'trello-minus'); _Util__WEBPACK_IMPORTED_MODULE_2__.Util.addClass(header, 'trello-plus'); } }); board_view.presentCard(expander, sprint.start_meeting); board_view.presentCard(expander, sprint.end_meeting); // // Completed // var pCompleted = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('p', 'trello-completed-header'); expander.appendChild(pCompleted); pCompleted.innerText = 'Sprint Completed Tasks'; var pMembers = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('p', 'trello-count'); expander.appendChild(pMembers); var members = '<em>Completed:</em>[' + sprint.completed.length + '] '; for (var c in counts) { if (counts.hasOwnProperty(c)) { members += counts[c].member.name + ':[' + counts[c].cnt + ']&nbsp;&nbsp;'; } } pMembers.innerHTML = members; // // Present completed cards // for (var i = 0; i < sprint.completed.length; i++) { var _completed = sprint.completed[i]; board_view.presentCard(expander, _completed); } }; var present_members = function present_members(div, sprints) { var membersDiv = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-members'); div.appendChild(membersDiv); for (var id in sprints.members) { if (sprints.members.hasOwnProperty(id)) { var member = sprints.members[id]; present_member(membersDiv, sprints, member); } } present_info(membersDiv, sprints); }; var present_member = function present_member(div, sprints, member) { var memberDiv = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-member'); div.appendChild(memberDiv); var meetings = sprints.meetings_slop === 1 ? ' meeting' : ' meetings'; var teamSize = sprints.num_members(); memberDiv.innerHTML = '<h4>' + member.member.name + '</h4>' + '<p>Meetings attended: ' + member.meetings_attended + '/' + member.meetings_count + ' percentage: ' + member.meetings_percentage() + ' <em>You are allowed to miss ' + sprints.meetings_slop + meetings + '</em>' + '</p>' + '<p>Tasks completed: ' + member.completed_count + '/' + (member.completed_total / teamSize).toFixed(2) + ' for a completion factor of: ' + member.completed_factor(teamSize) + '</p>' + '<p>Reviews completed: ' + member.reviews_count + ' for a reviewing factor of: ' + member.reviewing_factor(teamSize) + '</p>'; }; var present_info = function present_info(div, sprints) { var infoDiv = _Util__WEBPACK_IMPORTED_MODULE_2__.Util.createElement('div', 'trello-info'); div.appendChild(infoDiv); infoDiv.innerHTML = '<p>The completion factor for tasks is based on a metric that every' + ' team member is expected to complete ' + (sprints.completed_factor * 100).toFixed(0) + '% of' + ' an equal distribution of tasks. Values less than 1.00 indicate that you will be' + ' losing points on the assignment.</p>' + '<p>The reviewing factor for tasks is based on a metric that every team member' + ' is expected to review ' + (sprints.reviewing_factor * 100).toFixed(0) + '% of an equal' + ' distribution of tasks. This factor is based on a metric that 90% of tasks should' + ' be programming tasks. Values less than 1.00 indicate that you will be' + ' losing points on the assignment.</p>'; }; }; /// @cond SprintView.prototype = Object.create(_DataView__WEBPACK_IMPORTED_MODULE_0__.DataView.prototype); SprintView.prototype.constructor = SprintView; /// @endcond /***/ }), /***/ "./src/Sprints/Sprints.js": /*!********************************!*\ !*** ./src/Sprints/Sprints.js ***! \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Sprints": () => (/* binding */ Sprints) /* harmony export */ }); /* harmony import */ var _Sprint__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Sprint */ "./src/Sprints/Sprint.js"); /* harmony import */ var _SprintMember__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./SprintMember */ "./src/Sprints/SprintMember.js"); function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } /* * Sprint analysis of Trello board */ var Sprints = function Sprints(board) { var that = this; /// Number of missed meetings allow this.meetings_slop = 1; /// Number of seconds after meeting time to consider completed /// in a current sprint in seconds. this.sprint_time_slop = 5 * 60 * 60; // 5 hours /// Each users is expected to complete 80% of his share of tasks this.completed_factor = 0.8; /// Each users is expected to complete 80% of 90% of the task count in reviews this.reviewing_factor = 0.8 * 0.9; this.board = board; this.errors = []; this.warnings = []; this.members = {}; this.sprints = []; this.design = null; this.risks = null; this.meetings = null; this.todo = null; this.sprint_active = null; this.sprint_completed = null; this.completed = null; // // Copy over the members // for (var id in board.members) { var member = board.members[id]; if (member.name.toLowerCase() === "cse335") { continue; } this.members[id] = new _SprintMember__WEBPACK_IMPORTED_MODULE_1__.SprintMember(this, member); } // // Find all of the required lists // this.find_lists(); if (this.errors.length > 0) { this.error('e900'); return; } // // Order testing // this.order_test(); // // Determine attendance // this.meeting_attendance(); // // Convert meetings into sprints // this.create_sprints(); // // Sort completed into sprints // this.sort_completed(); // // Completed statistics // this.completed_statistics(); }; /** * Ensure all required lists exist. */ Sprints.prototype.find_lists = function () { // Find the "Design" list this.design = this.board.find_list('Design'); if (this.design === null) { this.error('e001'); } // Find the "Risks" list this.risks = this.board.find_list('Risks'); if (this.risks === null) { this.error('e002'); } // Find the "Meetings" list this.meetings = this.board.find_list('Meetings'); if (this.meetings === null) { this.error('e003'); } // Find the "To Do" list this.todo = this.board.find_list('To Do'); if (this.todo === null) { this.error('e004'); } // Find the "This Sprint Active" list this.sprint_active = this.board.find_list('This Sprint Active'); if (this.sprint_active === null) { this.error('e005'); } // Find the "This Sprint Completed" list this.sprint_completed = this.board.find_list('This Sprint Completed'); if (this.sprint_completed === null) {