diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index ca44a991257..c8c85f4ec91 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -35,7 +35,7 @@ $(function () { const boards = resp.json(); boards.forEach((board) => { - const list = BoardsStore.new(board, false); + const list = BoardsStore.addList(board); if (list.type === 'done') { list.position = 9999999; diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6 index 1f3a417aecd..ff9bffafd99 100644 --- a/app/assets/javascripts/boards/components/board.js.es6 +++ b/app/assets/javascripts/boards/components/board.js.es6 @@ -45,7 +45,6 @@ group: 'boards', draggable: '.is-draggable', handle: '.js-board-handle', - filter: '.board-delete', onUpdate: function (e) { BoardsStore.moveList(e.oldIndex, e.newIndex); } diff --git a/app/assets/javascripts/boards/components/board_card.js.es6 b/app/assets/javascripts/boards/components/board_card.js.es6 new file mode 100644 index 00000000000..14191cb881b --- /dev/null +++ b/app/assets/javascripts/boards/components/board_card.js.es6 @@ -0,0 +1,25 @@ +(() => { + const BoardCard = Vue.extend({ + props: { + issue: Object, + issueLinkBase: String, + disabled: Boolean + }, + methods: { + filterByLabel: function (label, $event) { + const labelIndex = BoardsStore.state.filters['label_name'].indexOf(label.title); + // $($event.target).tooltip('hide'); + + if (labelIndex === -1) { + BoardsStore.state.filters['label_name'].push(label.title); + } else { + BoardsStore.state.filters['label_name'].splice(labelIndex, 1); + } + + BoardsStore.updateFiltersUrl(); + } + } + }); + + Vue.component('board-card', BoardCard); +})(); diff --git a/app/assets/javascripts/boards/components/board_delete.js.es6 b/app/assets/javascripts/boards/components/board_delete.js.es6 index b9afb5724f5..958d85cd326 100644 --- a/app/assets/javascripts/boards/components/board_delete.js.es6 +++ b/app/assets/javascripts/boards/components/board_delete.js.es6 @@ -1,14 +1,14 @@ (() => { const BoardDelete = Vue.extend({ props: { - boardId: Number + list: Object }, methods: { deleteBoard: function () { $(this.$el).tooltip('destroy'); if (confirm('Are you sure you want to delete this list?')) { - BoardsStore.removeList(this.boardId); + this.list.destroy(); } } } diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 b/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 index 2b2620fd8a1..4509589edf2 100644 --- a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 +++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 @@ -8,6 +8,7 @@ fallbackClass: 'is-dragging', fallbackOnBody: true, ghostClass: 'is-ghost', + filter: '.has-tooltip', scrollSensitivity: 50, scrollSpeed: 10, onStart: function () { diff --git a/app/assets/javascripts/boards/models/label.js.es6 b/app/assets/javascripts/boards/models/label.js.es6 index d2ce30c37ea..99daf093d37 100644 --- a/app/assets/javascripts/boards/models/label.js.es6 +++ b/app/assets/javascripts/boards/models/label.js.es6 @@ -3,5 +3,6 @@ class Label { this.id = obj.id; this.title = obj.title; this.color = obj.color; + this.description = obj.description; } } diff --git a/app/assets/javascripts/boards/models/list.js.es6 b/app/assets/javascripts/boards/models/list.js.es6 index c2b06e4ed73..60214e2c798 100644 --- a/app/assets/javascripts/boards/models/list.js.es6 +++ b/app/assets/javascripts/boards/models/list.js.es6 @@ -33,6 +33,11 @@ class List { destroy () { if (this.type !== 'blank') { + BoardsStore.state.lists = _.reject(BoardsStore.state.lists, (list) => { + return list.id === this.id; + }); + BoardsStore.updateNewListDropdown(); + gl.boardService.destroyList(this.id); } } diff --git a/app/assets/javascripts/boards/stores/boards_store.js.es6 b/app/assets/javascripts/boards/stores/boards_store.js.es6 index fe2b11a9a8e..84acbeef102 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js.es6 +++ b/app/assets/javascripts/boards/stores/boards_store.js.es6 @@ -11,53 +11,51 @@ label_name: gl.utils.getParameterValues('label_name[]') }; }, - new: function (board, persist = true) { - const doneList = this.findList('type', 'done'), - backlogList = this.findList('type', 'backlog'), - list = new List(board); + addList: function (listObj) { + const list = new List(listObj); this.state.lists.push(list); - if (persist) { - list - .save() - .then(function () { - // Remove any new issues from the backlog - // as they will be visible in the new list - _.each(list.issues, backlogList.removeIssue.bind(backlogList)); - }); - this.removeBlankState(); - } - return list; }, + new: function (listObj) { + const list = this.addList(listObj), + backlogList = this.findList('type', 'backlog'); + + list + .save() + .then(function () { + // Remove any new issues from the backlog + // as they will be visible in the new list + _.each(list.issues, backlogList.removeIssue.bind(backlogList)); + }); + this.removeBlankState(); + }, updateNewListDropdown: function () { const data = $('.js-new-board-list').data('glDropdown').renderedData; - $('.js-new-board-list').data('glDropdown').renderData(data); + + if (data) { + $('.js-new-board-list').data('glDropdown').renderData(data); + } }, shouldAddBlankState: function () { // Decide whether to add the blank state - let addBlankState = _.find(this.state.lists, function (list) { + return !_.find(this.state.lists, function (list) { return list.type === 'backlog' || list.type === 'done'; }); - return !addBlankState; }, addBlankState: function () { - const addBlankState = this.shouldAddBlankState(); - if (this.welcomeIsHidden() || this.disabled) return; - if (addBlankState) { - this.new({ + if (this.shouldAddBlankState()) { + this.addList({ id: 'blank', list_type: 'blank', title: 'Welcome to your Issue Board!', position: 0 - }, false); + }); } }, removeBlankState: function () { - if (this.welcomeIsHidden()) return; - this.removeList('blank'); $.cookie('issue_board_welcome_hidden', 'true', { @@ -72,13 +70,9 @@ if (!list) return; - list.destroy(); - - this.state.lists = _.reject(this.state.lists, function (list) { + this.state.lists = _.reject(this.state.lists, (list) => { return list.id === id; }); - - this.updateNewListDropdown(); }, moveList: function (oldIndex, newIndex) { if (oldIndex === newIndex) return; diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index 1af91f001b5..364e5a41bb0 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -250,6 +250,11 @@ a { cursor: pointer; } + + .label { + border: 0; + outline: 0; + } } .card-title { diff --git a/app/views/projects/boards/components/_board.html.haml b/app/views/projects/boards/components/_board.html.haml index f7f1fb832c8..baf367af676 100644 --- a/app/views/projects/boards/components/_board.html.haml +++ b/app/views/projects/boards/components/_board.html.haml @@ -6,12 +6,14 @@ .board{ ":class" => "{ 'is-draggable': !isPreset }" } .board-inner %header.board-header{ ":class" => "{ 'has-border': list.label }", ":style" => "{ borderTopColor: (list.label ? list.label.color : null) }" } - %h3.board-title.js-board-handle{ ":class" => "{ 'user-can-drag': !disabled }" } + %h3.board-title.js-board-handle{ ":class" => "{ 'user-can-drag': (!disabled && !isPreset) }" } {{ list.title }} %span.pull-right{ "v-if" => "list.type !== 'blank'" } {{ list.issues.length }} - if current_user - %board-delete{ "inline-template" => true, "v-if" => "!isPreset", ":board-id" => "list.id" } + %board-delete{ "inline-template" => true, + "v-if" => "!isPreset", + ":list" => "list" } %button.board-delete.has-tooltip.pull-right{ type: "button", title: "Delete list", "aria-label" => "Delete list", data: { placement: "bottom" }, "@click" => "deleteBoard" } = icon("trash") .board-inner-container.board-search-container{ "v-if" => "list.canSearch()" } diff --git a/app/views/projects/boards/components/_card.html.haml b/app/views/projects/boards/components/_card.html.haml index 447b8af3991..a7000607f1c 100644 --- a/app/views/projects/boards/components/_card.html.haml +++ b/app/views/projects/boards/components/_card.html.haml @@ -1,19 +1,26 @@ -%li.card{ ":data-issue" => "issue.id", +%board-card{ "inline-template" => true, "v-for" => "issue in issues | orderBy 'id' -1", - "track-by" => "id", - ":class" => "{ 'user-can-drag': !disabled }" } - %h4.card-title - %a{ ":href" => "issueLinkBase + '/' + issue.id", - ":title" => "issue.title" } - {{ issue.title }} - .card-footer - %span.card-number - = precede '#' do - {{ issue.id }} - %span.label.color-label{ "v-for" => "label in issue.labels", - ":style" => "{ backgroundColor: label.color, color: label.textColor }" } - {{ label.title }} - %a.has-tooltip{ ":href" => "'/u/' + issue.assignee.username", - ":title" => "'Assigned to ' + issue.assignee.name", - "v-if" => "issue.assignee" } - %img.avatar.avatar-inline.s20{ ":src" => "issue.assignee.avatar", width: 20, height: 20 } + ":issue" => "issue", + ":issue-link-base" => "issueLinkBase", + ":disabled" => "disabled", + "track-by" => "id" } + %li.card{ ":data-issue" => "issue.id", + ":class" => "{ 'user-can-drag': !disabled }" } + %h4.card-title + %a{ ":href" => "issueLinkBase + '/' + issue.id", + ":title" => "issue.title" } + {{ issue.title }} + .card-footer + %span.card-number + = precede '#' do + {{ issue.id }} + %button.label.color-label.has-tooltip{ "v-for" => "label in issue.labels", + type: "button", + "@click" => "filterByLabel(label, $event)", + ":style" => "{ backgroundColor: label.color, color: label.textColor }", + ":title" => "label.description" } + {{ label.title }} + %a.has-tooltip{ ":href" => "'/u/' + issue.assignee.username", + ":title" => "'Assigned to ' + issue.assignee.name", + "v-if" => "issue.assignee" } + %img.avatar.avatar-inline.s20{ ":src" => "issue.assignee.avatar", width: 20, height: 20 }