Expand/collapse close & backlog lists in issue boards
The closed & backlog lists in issue boards are no collapsible. They can be collapsed independently of each other & this selection is then saved to the browser through localStorage. When the page loads, the code gets the data from localStorage & determines whether to show or hide the list Closes #23917
This commit is contained in:
parent
8039b9c3c6
commit
f452c1aa7d
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable comma-dangle, space-before-function-paren, one-var */
|
||||
/* global Sortable */
|
||||
import Vue from 'vue';
|
||||
import AccessorUtilities from '../../lib/utils/accessor';
|
||||
import boardList from './board_list';
|
||||
import boardBlankState from './board_blank_state';
|
||||
import './board_delete';
|
||||
|
@ -22,6 +23,10 @@ gl.issueBoards.Board = Vue.extend({
|
|||
disabled: Boolean,
|
||||
issueLinkBase: String,
|
||||
rootPath: String,
|
||||
boardId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -78,8 +83,14 @@ gl.issueBoards.Board = Vue.extend({
|
|||
methods: {
|
||||
showNewIssueForm() {
|
||||
this.$refs['board-list'].showIssueForm = !this.$refs['board-list'].showIssueForm;
|
||||
},
|
||||
toggleExpanded(e) {
|
||||
if (this.list.isExpandable && !e.target.classList.contains('js-no-trigger-collapse')) {
|
||||
this.list.isExpanded = !this.list.isExpanded;
|
||||
localStorage.setItem(`boards.${this.boardId}.${this.list.type}.expanded`, this.list.isExpanded);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.sortableOptions = gl.issueBoards.getBoardSortableDefaultOptions({
|
||||
disabled: this.disabled,
|
||||
|
@ -102,4 +113,11 @@ gl.issueBoards.Board = Vue.extend({
|
|||
|
||||
this.sortable = Sortable.create(this.$el.parentNode, this.sortableOptions);
|
||||
},
|
||||
created() {
|
||||
if (this.list.isExpandable && AccessorUtilities.isLocalStorageAccessSafe()) {
|
||||
const isCollapsed = localStorage.getItem(`boards.${this.boardId}.${this.list.type}.expanded`) === 'false';
|
||||
|
||||
this.list.isExpanded = !isCollapsed;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,7 +12,9 @@ class List {
|
|||
this.position = obj.position;
|
||||
this.title = obj.title;
|
||||
this.type = obj.list_type;
|
||||
this.preset = ['closed', 'blank'].indexOf(this.type) > -1;
|
||||
this.preset = ['backlog', 'closed', 'blank'].indexOf(this.type) > -1;
|
||||
this.isExpandable = ['backlog', 'closed'].indexOf(this.type) > -1;
|
||||
this.isExpanded = true;
|
||||
this.page = 1;
|
||||
this.loading = true;
|
||||
this.loadingMore = false;
|
||||
|
|
|
@ -31,10 +31,14 @@ gl.issueBoards.BoardsStore = {
|
|||
},
|
||||
new (listObj) {
|
||||
const list = this.addList(listObj);
|
||||
const backlogList = this.findList('type', 'backlog', 'backlog');
|
||||
|
||||
list
|
||||
.save()
|
||||
.then(() => {
|
||||
// Remove any new issues from the backlog
|
||||
// as they will be visible in the new list
|
||||
list.issues.forEach(backlogList.removeIssue.bind(backlogList));
|
||||
this.state.lists = _.sortBy(this.state.lists, 'position');
|
||||
})
|
||||
.catch(() => {
|
||||
|
@ -47,7 +51,7 @@ gl.issueBoards.BoardsStore = {
|
|||
},
|
||||
shouldAddBlankState () {
|
||||
// Decide whether to add the blank state
|
||||
return !(this.state.lists.filter(list => list.type !== 'closed')[0]);
|
||||
return !(this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'done')[0]);
|
||||
},
|
||||
addBlankState () {
|
||||
if (!this.shouldAddBlankState() || this.welcomeIsHidden() || this.disabled) return;
|
||||
|
@ -100,7 +104,7 @@ gl.issueBoards.BoardsStore = {
|
|||
issueTo.removeLabel(listFrom.label);
|
||||
}
|
||||
|
||||
if (listTo.type === 'closed') {
|
||||
if (listTo.type === 'closed' && listFrom.type !== 'backlog') {
|
||||
issueLists.forEach((list) => {
|
||||
list.removeIssue(issue);
|
||||
});
|
||||
|
|
|
@ -96,9 +96,51 @@
|
|||
@media (min-width: $screen-sm-min) {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
&.is-expandable {
|
||||
.board-header {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
width: 60px;
|
||||
|
||||
.board-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.board-title {
|
||||
position: initial;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
transform: rotate(90deg) translate(25px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.board-title-expandable-toggle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.board-list-component,
|
||||
.board-issue-count-holder {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.board-inner {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
font-size: $issue-boards-font-size;
|
||||
background: $gray-light;
|
||||
|
|
|
@ -5,6 +5,8 @@ module Projects
|
|||
before_action :authorize_read_list!, only: [:index]
|
||||
|
||||
def index
|
||||
board.lists.create(list_type: :backlog) unless board.lists.backlog.any?
|
||||
|
||||
render json: serialize_as_json(board.lists)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ class Board < ActiveRecord::Base
|
|||
|
||||
validates :project, presence: true
|
||||
|
||||
def backlog_list
|
||||
lists.merge(List.backlog).take
|
||||
end
|
||||
|
||||
def closed_list
|
||||
lists.merge(List.closed).take
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ class List < ActiveRecord::Base
|
|||
belongs_to :board
|
||||
belongs_to :label
|
||||
|
||||
enum list_type: { label: 1, closed: 2 }
|
||||
enum list_type: { backlog: 0, label: 1, closed: 2 }
|
||||
|
||||
validates :board, :list_type, presence: true
|
||||
validates :label, :position, presence: true, if: :label?
|
||||
|
|
|
@ -12,6 +12,7 @@ module Boards
|
|||
|
||||
def create_board!
|
||||
board = project.boards.create
|
||||
board.lists.create(list_type: :backlog)
|
||||
board.lists.create(list_type: :closed)
|
||||
|
||||
board
|
||||
|
|
|
@ -3,7 +3,7 @@ module Boards
|
|||
class ListService < BaseService
|
||||
def execute
|
||||
issues = IssuesFinder.new(current_user, filter_params).execute
|
||||
issues = without_board_labels(issues) unless list
|
||||
issues = without_board_labels(issues) unless movable_list?
|
||||
issues = with_list_label(issues) if movable_list?
|
||||
issues.order_by_position_and_priority
|
||||
end
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
":disabled" => "disabled",
|
||||
":issue-link-base" => "issueLinkBase",
|
||||
":root-path" => "rootPath",
|
||||
":board-id" => "boardId",
|
||||
":key" => "_uid" }
|
||||
= render "projects/boards/components/sidebar"
|
||||
%board-add-issues-modal{ "blank-state-image" => render('shared/empty_states/icons/issues.svg'),
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
.board{ ":class" => '{ "is-draggable": !list.preset }',
|
||||
.board{ ":class" => '{ "is-draggable": !list.preset, "is-expandable": list.isExpandable, "is-collapsed": !list.isExpanded }',
|
||||
":data-id" => "list.id" }
|
||||
.board-inner
|
||||
%header.board-header{ ":class" => '{ "has-border": list.label }', ":style" => "{ borderTopColor: (list.label ? list.label.color : null) }" }
|
||||
%header.board-header{ ":class" => '{ "has-border": list.label && list.label.color }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }", "@click" => "toggleExpanded($event)" }
|
||||
%h3.board-title.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset) }' }
|
||||
%i.fa.fa-fw.board-title-expandable-toggle{ "v-if": "list.isExpandable",
|
||||
":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-left\": !list.isExpanded }",
|
||||
"aria-hidden": "true" }
|
||||
%span.has-tooltip{ ":title" => '(list.label ? list.label.description : "")',
|
||||
data: { container: "body", placement: "bottom" } }
|
||||
{{ list.title }}
|
||||
|
@ -10,13 +13,13 @@
|
|||
%span.board-issue-count.pull-left{ ":class" => '{ "has-btn": list.type !== "closed" && !disabled }' }
|
||||
{{ list.issuesSize }}
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
%button.btn.btn-small.btn-default.pull-right.has-tooltip{ type: "button",
|
||||
%button.btn.btn-small.btn-default.pull-right.has-tooltip.js-no-trigger-collapse{ type: "button",
|
||||
"@click" => "showNewIssueForm",
|
||||
"v-if" => 'list.type !== "closed"',
|
||||
"aria-label" => "New issue",
|
||||
"title" => "New issue",
|
||||
data: { placement: "top", container: "body" } }
|
||||
= icon("plus")
|
||||
= icon("plus", class: "js-no-trigger-collapse")
|
||||
- if can?(current_user, :admin_list, @project)
|
||||
%board-delete{ "inline-template" => true,
|
||||
":list" => "list",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Expand/collapse backlog & closed lists in issue boards
|
||||
merge_request:
|
||||
author:
|
Loading…
Reference in New Issue