diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index b3dbf8270a8839fd972dabe636a484a00d44f360..d01d863361186e227e8fb43f24aaef01ccf0c0b7 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -1,6 +1,7 @@ //= require vue //= require vue-resource //= require Sortable +//= require_tree ./models //= require_tree ./stores //= require_tree ./services //= require_tree ./components @@ -16,8 +17,8 @@ $(function () { ready: function () { service.all() .then((resp) => { - resp.data.forEach((board) => { - BoardsStore.state.lists.push(board); + resp.json().forEach((board) => { + BoardsStore.new(board); }); }); } diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6 index 75fdf61821d2e3c011420c4889718eed1967f60d..9836790eb74fd791af6d18c3a6c7707ef9112990 100644 --- a/app/assets/javascripts/boards/components/board.js.es6 +++ b/app/assets/javascripts/boards/components/board.js.es6 @@ -27,7 +27,7 @@ fallbackClass: 'is-dragging', ghostClass: 'is-ghost', onUpdate: function (e) { - BoardsStore.moveBoard(e.oldIndex + 1, e.newIndex + 1); + BoardsStore.moveList(e.oldIndex + 1, e.newIndex + 1); } }); }, diff --git a/app/assets/javascripts/boards/components/board_delete.js.es6 b/app/assets/javascripts/boards/components/board_delete.js.es6 index 75157f8ff3381de92ac22431cd8c46d87aee0929..cff93f226128cb9136d268ce0f4de53654d97521 100644 --- a/app/assets/javascripts/boards/components/board_delete.js.es6 +++ b/app/assets/javascripts/boards/components/board_delete.js.es6 @@ -8,7 +8,7 @@ $(this.$el).tooltip('destroy'); if (confirm('Are you sure you want to delete this list?')) { - BoardsStore.removeBoard(this.boardId); + BoardsStore.removeList(this.boardId); } } } diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6 index ea40563ebe946af3b801fadf75895cc16e9cd026..942382ff543a65b2a47e3ce9a966caf97df641b6 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js.es6 @@ -62,13 +62,13 @@ fallbackClass: 'is-dragging', ghostClass: 'is-ghost', onAdd: (e) => { - let fromBoardId = e.from.getAttribute('data-board'); - fromBoardId = parseInt(fromBoardId) || fromBoardId; - let toBoardId = e.to.getAttribute('data-board'); - toBoardId = parseInt(toBoardId) || toBoardId; + let fromListId = e.from.getAttribute('data-board'); + fromListId = parseInt(fromListId) || fromListId; + let toListId = e.to.getAttribute('data-board'); + toListId = parseInt(toListId) || toListId; const issueId = parseInt(e.item.getAttribute('data-issue')); - BoardsStore.moveCardToBoard(fromBoardId, toBoardId, issueId, e.newIndex); + BoardsStore.moveCardToList(fromListId, toListId, issueId, e.newIndex); }, onUpdate: (e) => { console.log(e.newIndex, e.oldIndex); diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 b/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 new file mode 100644 index 0000000000000000000000000000000000000000..0796a95219ee16a1aaf0987b1c739f88603f0dec --- /dev/null +++ b/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 @@ -0,0 +1,32 @@ +$(() => { + $('.js-new-board-list').each(function () { + const $this = $(this); + + $this.glDropdown({ + data: function(term, callback) { + $.ajax({ + url: $this.attr('data-labels') + }).then((resp) => { + callback(resp); + }); + }, + renderRow: (label) => { + const $li = $('<li />'), + $a = $('<a />', { + text: label.title, + href: '#' + }), + $labelColor = $('<span />', { + class: 'dropdown-label-box', + style: `background-color: ${label.color}` + }); + + return $li.append($a.prepend($labelColor)); + }, + selectable: true, + clicked: (label, $el, e) => { + e.preventDefault(); + } + }); + }); +}); diff --git a/app/assets/javascripts/boards/models/issue.js.es6 b/app/assets/javascripts/boards/models/issue.js.es6 new file mode 100644 index 0000000000000000000000000000000000000000..a8fed848445c27ff2d37ad41a315992020e5d852 --- /dev/null +++ b/app/assets/javascripts/boards/models/issue.js.es6 @@ -0,0 +1,35 @@ +class Issue { + constructor (obj) { + this.id = obj.id; + this.title = obj.title; + this.labels = []; + + obj.labels.forEach((label) => { + this.labels.push(new Label(label)); + }); + } + + addLabel (label) { + if (label) { + const hasLabel = this.findLabel(label); + + if (!hasLabel) { + this.labels.push(new Label(label)); + } + } + } + + findLabel (findLabel) { + return _.find(this.labels, (label) => { + return label.title === findLabel.title; + }); + } + + removeLabel (removeLabel) { + if (removeLabel) { + this.labels = _.reject(this.labels, (label) => { + return removeLabel.title === label.title; + }); + } + } +} diff --git a/app/assets/javascripts/boards/models/label.js.es6 b/app/assets/javascripts/boards/models/label.js.es6 new file mode 100644 index 0000000000000000000000000000000000000000..93da376de7cbd054f8ec85eac5c1bef8cdafbfc9 --- /dev/null +++ b/app/assets/javascripts/boards/models/label.js.es6 @@ -0,0 +1,7 @@ +class Label { + constructor (obj) { + this.title = obj.title; + this.backgroundColor = obj.backgroundColor; + this.textColor = obj.textColor; + } +} diff --git a/app/assets/javascripts/boards/models/list.js.es6 b/app/assets/javascripts/boards/models/list.js.es6 new file mode 100644 index 0000000000000000000000000000000000000000..ebef8bc6fd70ddd00efab897674092cd88f4b6fa --- /dev/null +++ b/app/assets/javascripts/boards/models/list.js.es6 @@ -0,0 +1,49 @@ +class List { + constructor (obj) { + this.id = obj.id; + this.index = obj.index; + this.search = obj.search || false; + this.title = obj.title; + + if (obj.label) { + this.label = new Label(obj.label); + } + + if (obj.issues) { + this.issues = []; + obj.issues.forEach((issue) => { + this.issues.push(new Issue(issue)); + }); + } + } + + addIssue (issue, index) { + this.issues.splice(index, 0, issue); + + issue.addLabel(this.label); + } + + findIssue (id) { + return _.find(this.issues, (issue) => { + return issue.id === id; + }); + } + + removeIssue (removeIssue, listLabels) { + this.issues = _.reject(this.issues, (issue) => { + const matchesRemove = removeIssue.id === issue.id; + + if (matchesRemove) { + if (typeof listLabels !== 'undefined') { + listLabels.forEach((listLabel) => { + issue.removeLabel(listLabel); + }); + } else { + issue.removeLabel(this.label); + } + } + + return matchesRemove; + }); + } +} diff --git a/app/assets/javascripts/boards/stores/boards_store.js.es6 b/app/assets/javascripts/boards/stores/boards_store.js.es6 index 6e5da9ea9f0cbaf340546c16e53101f2543292a3..be80447d0d7d30fd4f94e19df64a5996b97a365c 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js.es6 +++ b/app/assets/javascripts/boards/stores/boards_store.js.es6 @@ -9,103 +9,63 @@ milestone: {}, } }, - removeBoard: (id) => { - BoardsStore.state.lists = _.reject(BoardsStore.state.lists, (board) => { - return board.id === id; + new: function (board) { + const list = new List(board); + this.state.lists.push(list); + }, + removeList: function (id) { + this.state.lists = _.reject(this.state.lists, (list) => { + return list.id === id; }); }, - moveBoard: (oldIndex, newIndex) => { - const boardFrom = _.find(BoardsStore.state.lists, (board) => { - return board.index === oldIndex; + moveList: function (oldIndex, newIndex) { + const listFrom = _.find(this.state.lists, (list) => { + return list.index === oldIndex; }); - service.updateBoard(boardFrom.id, newIndex); + service.updateBoard(listFrom.id, newIndex); - const boardTo = _.find(BoardsStore.state.lists, (board) => { - return board.index === newIndex; + const listTo = _.find(this.state.lists, (list) => { + return list.index === newIndex; }); - boardFrom.index = newIndex; - if (newIndex > boardTo.index) { - boardTo.index--; + listFrom.index = newIndex; + if (newIndex > listTo.index) { + listTo.index--; } else { - boardTo.index++; + listTo.index++; } }, - moveCardToBoard: (boardFromId, boardToId, issueId, toIndex) => { - const boardFrom = _.find(BoardsStore.state.lists, (board) => { - return board.id === boardFromId; - }); - const boardTo = _.find(BoardsStore.state.lists, (board) => { - return board.id === boardToId; - }); - let issue = _.find(boardFrom.issues, (issue) => { - return issue.id === issueId; + moveCardToList: function (listFromId, listToId, issueId, toIndex) { + const listFrom = _.find(this.state.lists, (list) => { + return list.id === listFromId; }); - const issueTo = _.find(boardTo.issues, (issue) => { - return issue.id === issueId; - }); - const issueBoards = BoardsStore.getBoardsForIssue(issue); - - // Remove the issue from old board - boardFrom.issues = _.reject(boardFrom.issues, (issue) => { - return issue.id === issueId; + const listTo = _.find(this.state.lists, (list) => { + return list.id === listToId; }); + const issueTo = listTo.findIssue(issueId); + let issue = listFrom.findIssue(issueId); + const issueLists = this.getListsForIssue(issue); + listFrom.removeIssue(issue); // Add to new boards issues if it doesn't already exist if (issueTo) { issue = issueTo; + issue.removeLabel(listFrom.label); } else { - boardTo.issues.splice(toIndex, 0, issue); + listTo.addIssue(issue, toIndex); } - if (boardTo.id === 'done' && boardFrom.id !== 'backlog') { - BoardsStore.removeIssueFromBoards(issue, issueBoards); - issue.labels = _.reject(issue.labels, (label) => { - return label.title === boardFrom.title; + if (listTo.id === 'done' && listFrom.id !== 'backlog') { + issueLists.forEach((list) => { + issue.removeLabel(list.label); + list.removeIssue(issue); }); - } else { - if (boardTo.label) { - if (boardFrom.id !== 'backlog') { - BoardsStore.removeIssueFromBoard(issue, boardFrom); - } - - foundLabel = _.find(issue.labels, (label) => { - return label.title === boardTo.title; - }); - - if (!foundLabel) { - issue.labels.push(boardTo.label); - } - } } }, - removeIssueFromBoards: (issue, boards) => { - const boardLabels = _.map(boards, (board) => { - return board.title; - }); - - boards.issues = _.each(boards, (board) => { - board.issues = _.reject(board.issues, (boardIssue) => { - return issue.id === boardIssue.id; - }); - }); - - issue.labels = _.reject(issue.labels, (label) => { - return boardLabels.indexOf(label.title) !== -1; - }); - }, - removeIssueFromBoard: (issue, board) => { - issue.labels = _.reject(issue.labels, (label) => { - return label.title === board.title; - }); - }, - getBoardsForIssue: (issue) => { - return _.filter(BoardsStore.state.lists, (board) => { - const foundIssue = _.find(board.issues, (boardIssue) => { - return issue.id === boardIssue.id; - }); - return foundIssue; + getListsForIssue: function (issue) { + return _.filter(this.state.lists, (list) => { + return list.findIssue(issue.id); }); }, clearDone: () => { diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index a06679f599d055238746478f13e06a1307a4d63f..773f3975816be7f0fb55f4ef75e57e0db1c3445b 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -31,7 +31,7 @@ = render 'shared/sort_dropdown' - else .dropdown - %button.btn.btn-create{ type: "button", data: { toggle: "dropdown" } } + %button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path } } Create new list .dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new = dropdown_title("Create a new list")