Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
5815c5b4
Commit
5815c5b4
authored
Jul 30, 2018
by
Felipe Artur
Committed by
Phil Hughes
Jul 30, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Backport] View summed weights of issues in board column
parent
4f083434
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
113 additions
and
46 deletions
+113
-46
app/assets/javascripts/boards/components/board.js
app/assets/javascripts/boards/components/board.js
+13
-0
app/assets/javascripts/boards/models/list.js
app/assets/javascripts/boards/models/list.js
+2
-0
app/assets/javascripts/boards/stores/boards_store.js
app/assets/javascripts/boards/stores/boards_store.js
+8
-2
app/assets/stylesheets/framework/typography.scss
app/assets/stylesheets/framework/typography.scss
+2
-0
app/assets/stylesheets/pages/boards.scss
app/assets/stylesheets/pages/boards.scss
+1
-1
app/assets/stylesheets/pages/issues/issue_count_badge.scss
app/assets/stylesheets/pages/issues/issue_count_badge.scss
+4
-22
app/controllers/boards/issues_controller.rb
app/controllers/boards/issues_controller.rb
+11
-6
app/services/boards/issues/list_service.rb
app/services/boards/issues/list_service.rb
+24
-3
app/views/shared/boards/components/_board.html.haml
app/views/shared/boards/components/_board.html.haml
+14
-10
spec/controllers/boards/issues_controller_spec.rb
spec/controllers/boards/issues_controller_spec.rb
+2
-2
spec/javascripts/boards/boards_store_spec.js
spec/javascripts/boards/boards_store_spec.js
+22
-0
spec/support/shared_examples/services/boards/issues_list_service.rb
...rt/shared_examples/services/boards/issues_list_service.rb
+10
-0
No files found.
app/assets/javascripts/boards/components/board.js
View file @
5815c5b4
...
@@ -2,6 +2,9 @@
...
@@ -2,6 +2,9 @@
import
Sortable
from
'
sortablejs
'
;
import
Sortable
from
'
sortablejs
'
;
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
n__
}
from
'
~/locale
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
AccessorUtilities
from
'
../../lib/utils/accessor
'
;
import
AccessorUtilities
from
'
../../lib/utils/accessor
'
;
import
boardList
from
'
./board_list.vue
'
;
import
boardList
from
'
./board_list.vue
'
;
import
BoardBlankState
from
'
./board_blank_state.vue
'
;
import
BoardBlankState
from
'
./board_blank_state.vue
'
;
...
@@ -17,6 +20,10 @@ gl.issueBoards.Board = Vue.extend({
...
@@ -17,6 +20,10 @@ gl.issueBoards.Board = Vue.extend({
boardList
,
boardList
,
'
board-delete
'
:
gl
.
issueBoards
.
BoardDelete
,
'
board-delete
'
:
gl
.
issueBoards
.
BoardDelete
,
BoardBlankState
,
BoardBlankState
,
Icon
,
},
directives
:
{
Tooltip
,
},
},
props
:
{
props
:
{
list
:
{
list
:
{
...
@@ -46,6 +53,12 @@ gl.issueBoards.Board = Vue.extend({
...
@@ -46,6 +53,12 @@ gl.issueBoards.Board = Vue.extend({
filter
:
Store
.
filter
,
filter
:
Store
.
filter
,
};
};
},
},
computed
:
{
counterTooltip
()
{
const
{
issuesSize
}
=
this
.
list
;
return
`
${
n__
(
'
%d issue
'
,
'
%d issues
'
,
issuesSize
)}
`
;
},
},
watch
:
{
watch
:
{
filter
:
{
filter
:
{
handler
()
{
handler
()
{
...
...
app/assets/javascripts/boards/models/list.js
View file @
5815c5b4
...
@@ -136,6 +136,8 @@ class List {
...
@@ -136,6 +136,8 @@ class List {
}
}
this
.
createIssues
(
data
.
issues
);
this
.
createIssues
(
data
.
issues
);
return
data
;
});
});
}
}
...
...
app/assets/javascripts/boards/stores/boards_store.js
View file @
5815c5b4
...
@@ -125,11 +125,17 @@ gl.issueBoards.BoardsStore = {
...
@@ -125,11 +125,17 @@ gl.issueBoards.BoardsStore = {
}
else
if
(
listTo
.
type
===
'
backlog
'
&&
listFrom
.
type
===
'
assignee
'
)
{
}
else
if
(
listTo
.
type
===
'
backlog
'
&&
listFrom
.
type
===
'
assignee
'
)
{
issue
.
removeAssignee
(
listFrom
.
assignee
);
issue
.
removeAssignee
(
listFrom
.
assignee
);
listFrom
.
removeIssue
(
issue
);
listFrom
.
removeIssue
(
issue
);
}
else
if
((
listTo
.
type
!==
'
label
'
&&
listFrom
.
type
===
'
assignee
'
)
||
}
else
if
(
this
.
shouldRemoveIssue
(
listFrom
,
listTo
))
{
(
listTo
.
type
!==
'
assignee
'
&&
listFrom
.
type
===
'
label
'
))
{
listFrom
.
removeIssue
(
issue
);
listFrom
.
removeIssue
(
issue
);
}
}
},
},
shouldRemoveIssue
(
listFrom
,
listTo
)
{
return
(
(
listTo
.
type
!==
'
label
'
&&
listFrom
.
type
===
'
assignee
'
)
||
(
listTo
.
type
!==
'
assignee
'
&&
listFrom
.
type
===
'
label
'
)
||
(
listFrom
.
type
===
'
backlog
'
)
);
},
moveIssueInList
(
list
,
issue
,
oldIndex
,
newIndex
,
idArray
)
{
moveIssueInList
(
list
,
issue
,
oldIndex
,
newIndex
,
idArray
)
{
const
beforeId
=
parseInt
(
idArray
[
newIndex
-
1
],
10
)
||
null
;
const
beforeId
=
parseInt
(
idArray
[
newIndex
-
1
],
10
)
||
null
;
const
afterId
=
parseInt
(
idArray
[
newIndex
+
1
],
10
)
||
null
;
const
afterId
=
parseInt
(
idArray
[
newIndex
+
1
],
10
)
||
null
;
...
...
app/assets/stylesheets/framework/typography.scss
View file @
5815c5b4
...
@@ -444,3 +444,5 @@ textarea {
...
@@ -444,3 +444,5 @@ textarea {
color
:
$placeholder-text-color
;
color
:
$placeholder-text-color
;
}
}
}
}
.lh-100
{
line-height
:
1
;
}
app/assets/stylesheets/pages/boards.scss
View file @
5815c5b4
...
@@ -205,7 +205,7 @@
...
@@ -205,7 +205,7 @@
.board-title
{
.board-title
{
margin
:
0
;
margin
:
0
;
padding
:
12px
$gl-padding
;
padding
:
$gl-padding-8
$gl-padding
;
font-size
:
1em
;
font-size
:
1em
;
border-bottom
:
1px
solid
$border-color
;
border-bottom
:
1px
solid
$border-color
;
display
:
flex
;
display
:
flex
;
...
...
app/assets/stylesheets/pages/issues/issue_count_badge.scss
View file @
5815c5b4
.issue-count-badge
{
.issue-count-badge
{
display
:
inline-flex
;
display
:
inline-flex
;
align-items
:
stretch
;
height
:
24px
;
}
.issue-count-badge-count
{
display
:
flex
;
align-items
:
center
;
padding-right
:
10px
;
padding-left
:
10px
;
border
:
1px
solid
$border-color
;
border-radius
:
$border-radius-base
;
border-radius
:
$border-radius-base
;
line-height
:
1
;
border
:
1px
solid
$border-color
;
padding
:
5px
$gl-padding-8
;
&
.has-btn
{
border-right
:
0
;
border-top-right-radius
:
0
;
border-bottom-right-radius
:
0
;
}
}
}
.issue-count-badge-
add-button
{
.issue-count-badge-
count
{
display
:
flex
;
display
:
inline-
flex
;
align-items
:
center
;
align-items
:
center
;
border
:
1px
solid
$border-color
;
border-radius
:
0
$border-radius-base
$border-radius-base
0
;
line-height
:
1
;
}
}
app/controllers/boards/issues_controller.rb
View file @
5815c5b4
...
@@ -12,8 +12,9 @@ module Boards
...
@@ -12,8 +12,9 @@ module Boards
skip_before_action
:authenticate_user!
,
only:
[
:index
]
skip_before_action
:authenticate_user!
,
only:
[
:index
]
def
index
def
index
issues
=
Boards
::
Issues
::
ListService
.
new
(
board_parent
,
current_user
,
filter_params
).
execute
list_service
=
Boards
::
Issues
::
ListService
.
new
(
board_parent
,
current_user
,
filter_params
)
issues
=
issues
.
page
(
params
[
:page
]).
per
(
params
[
:per
]
||
20
)
issues
=
list_service
.
execute
issues
=
issues
.
page
(
params
[
:page
]).
per
(
params
[
:per
]
||
20
).
without_count
make_sure_position_is_set
(
issues
)
if
Gitlab
::
Database
.
read_write?
make_sure_position_is_set
(
issues
)
if
Gitlab
::
Database
.
read_write?
issues
=
issues
.
preload
(
:project
,
issues
=
issues
.
preload
(
:project
,
:milestone
,
:milestone
,
...
@@ -22,10 +23,7 @@ module Boards
...
@@ -22,10 +23,7 @@ module Boards
notes:
[
:award_emoji
,
:author
]
notes:
[
:award_emoji
,
:author
]
)
)
render
json:
{
render_issues
(
issues
,
list_service
.
metadata
)
issues:
serialize_as_json
(
issues
),
size:
issues
.
total_count
}
end
end
def
create
def
create
...
@@ -51,6 +49,13 @@ module Boards
...
@@ -51,6 +49,13 @@ module Boards
private
private
def
render_issues
(
issues
,
metadata
)
data
=
{
issues:
serialize_as_json
(
issues
)
}
data
.
merge!
(
metadata
)
render
json:
data
end
def
make_sure_position_is_set
(
issues
)
def
make_sure_position_is_set
(
issues
)
issues
.
each
do
|
issue
|
issues
.
each
do
|
issue
|
issue
.
move_to_end
&&
issue
.
save
unless
issue
.
relative_position
issue
.
move_to_end
&&
issue
.
save
unless
issue
.
relative_position
...
...
app/services/boards/issues/list_service.rb
View file @
5815c5b4
...
@@ -3,14 +3,35 @@
...
@@ -3,14 +3,35 @@
module
Boards
module
Boards
module
Issues
module
Issues
class
ListService
<
Boards
::
BaseService
class
ListService
<
Boards
::
BaseService
include
Gitlab
::
Utils
::
StrongMemoize
def
execute
def
execute
issues
=
IssuesFinder
.
new
(
current_user
,
filter_params
).
execute
fetch_issues
.
order_by_position_and_priority
issues
=
filter
(
issues
)
end
issues
.
order_by_position_and_priority
def
metadata
keys
=
metadata_fields
.
keys
columns
=
metadata_fields
.
values_at
(
*
keys
).
join
(
', '
)
results
=
Issue
.
where
(
id:
fetch_issues
.
select
(
'issues.id'
)).
pluck
(
columns
)
Hash
[
keys
.
zip
(
results
.
flatten
)]
end
end
private
private
def
metadata_fields
{
size:
'COUNT(*)'
}
end
# We memoize the query here since the finder methods we use are quite complex. This does not memoize the result of the query.
def
fetch_issues
strong_memoize
(
:fetch_issues
)
do
issues
=
IssuesFinder
.
new
(
current_user
,
filter_params
).
execute
filter
(
issues
).
reorder
(
nil
)
end
end
def
filter
(
issues
)
def
filter
(
issues
)
issues
=
without_board_labels
(
issues
)
unless
list
&
.
movable?
||
list
&
.
closed?
issues
=
without_board_labels
(
issues
)
unless
list
&
.
movable?
||
list
&
.
closed?
issues
=
with_list_label
(
issues
)
if
list
&
.
label?
issues
=
with_list_label
(
issues
)
if
list
&
.
label?
...
...
app/views/shared/boards/components/_board.html.haml
View file @
5815c5b4
...
@@ -32,17 +32,21 @@
...
@@ -32,17 +32,21 @@
"v-if"
=>
"!list.preset && list.id"
}
"v-if"
=>
"!list.preset && list.id"
}
%button
.board-delete.has-tooltip.float-right
{
type:
"button"
,
title:
_
(
"Delete list"
),
"aria-label"
=>
_
(
"Delete list"
),
data:
{
placement:
"bottom"
},
"@click.stop"
=>
"deleteBoard"
}
%button
.board-delete.has-tooltip.float-right
{
type:
"button"
,
title:
_
(
"Delete list"
),
"aria-label"
=>
_
(
"Delete list"
),
data:
{
placement:
"bottom"
},
"@click.stop"
=>
"deleteBoard"
}
=
icon
(
"trash"
)
=
icon
(
"trash"
)
.issue-count-badge.clearfix
{
"v-if"
=>
'list.type !== "blank" && list.type !== "promotion"'
}
.issue-count-badge.text-secondary
{
"v-if"
=>
'list.type !== "blank" && list.type !== "promotion"'
,
":title"
:
"counterTooltip"
,
"v-tooltip"
:
true
,
data:
{
placement:
"top"
}
}
%span
.issue-count-badge-count.float-left
{
":class"
=>
'
{
"has-btn"
:
list
.
type
!==
"closed"
&&
!
disabled
}
'
}
%span
.issue-count-badge-count
%icon
.mr-1
{
name:
"issues"
}
{{ list.issuesSize }}
{{ list.issuesSize }}
=
render_if_exists
"shared/boards/components/list_weight"
-
if
can?
(
current_user
,
:admin_list
,
current_board_parent
)
-
if
can?
(
current_user
,
:admin_list
,
current_board_parent
)
%button
.issue-count-badge-add-button.btn.btn-sm.btn-default
.has-tooltip.js-no-trigger-collapse
{
type:
"button"
,
%button
.issue-count-badge-add-button.btn.btn-sm.btn-default.ml-1
.has-tooltip.js-no-trigger-collapse
{
type:
"button"
,
"@click"
=>
"showNewIssueForm"
,
"@click"
=>
"showNewIssueForm"
,
"v-if"
=>
'list.type !== "closed"'
,
"v-if"
=>
'list.type !== "closed"'
,
"aria-label"
=>
_
(
"New issue"
),
"aria-label"
=>
_
(
"New issue"
),
"title"
=>
_
(
"New issue"
),
"title"
=>
_
(
"New issue"
),
data:
{
placement:
"top"
,
container:
"body"
}
}
data:
{
placement:
"top"
,
container:
"body"
}
}
=
icon
(
"plus"
,
class:
"js-no-trigger-collapse"
)
=
icon
(
"plus"
,
class:
"js-no-trigger-collapse"
)
%board-list
{
"v-if"
=>
'list.type !== "blank" && list.type !== "promotion"'
,
%board-list
{
"v-if"
=>
'list.type !== "blank" && list.type !== "promotion"'
,
":list"
=>
"list"
,
":list"
=>
"list"
,
":issues"
=>
"list.issues"
,
":issues"
=>
"list.issues"
,
...
...
spec/controllers/boards/issues_controller_spec.rb
View file @
5815c5b4
...
@@ -42,7 +42,7 @@ describe Boards::IssuesController do
...
@@ -42,7 +42,7 @@ describe Boards::IssuesController do
parsed_response
=
JSON
.
parse
(
response
.
body
)
parsed_response
=
JSON
.
parse
(
response
.
body
)
expect
(
response
).
to
match_response_schema
(
'issues'
)
expect
(
response
).
to
match_response_schema
(
'issues'
)
expect
(
parsed_response
.
length
).
to
eq
2
expect
(
parsed_response
[
'issues'
]
.
length
).
to
eq
2
expect
(
development
.
issues
.
map
(
&
:relative_position
)).
not_to
include
(
nil
)
expect
(
development
.
issues
.
map
(
&
:relative_position
)).
not_to
include
(
nil
)
end
end
...
@@ -80,7 +80,7 @@ describe Boards::IssuesController do
...
@@ -80,7 +80,7 @@ describe Boards::IssuesController do
parsed_response
=
JSON
.
parse
(
response
.
body
)
parsed_response
=
JSON
.
parse
(
response
.
body
)
expect
(
response
).
to
match_response_schema
(
'issues'
)
expect
(
response
).
to
match_response_schema
(
'issues'
)
expect
(
parsed_response
.
length
).
to
eq
2
expect
(
parsed_response
[
'issues'
]
.
length
).
to
eq
2
end
end
end
end
...
...
spec/javascripts/boards/boards_store_spec.js
View file @
5815c5b4
...
@@ -161,6 +161,28 @@ describe('Store', () => {
...
@@ -161,6 +161,28 @@ describe('Store', () => {
},
0
);
},
0
);
});
});
it
(
'
moves an issue from backlog to a list
'
,
(
done
)
=>
{
const
backlog
=
gl
.
issueBoards
.
BoardsStore
.
addList
({
...
listObj
,
list_type
:
'
backlog
'
,
});
const
listTwo
=
gl
.
issueBoards
.
BoardsStore
.
addList
(
listObjDuplicate
);
expect
(
gl
.
issueBoards
.
BoardsStore
.
state
.
lists
.
length
).
toBe
(
2
);
setTimeout
(()
=>
{
expect
(
backlog
.
issues
.
length
).
toBe
(
1
);
expect
(
listTwo
.
issues
.
length
).
toBe
(
1
);
gl
.
issueBoards
.
BoardsStore
.
moveIssueToList
(
backlog
,
listTwo
,
backlog
.
findIssue
(
1
));
expect
(
backlog
.
issues
.
length
).
toBe
(
0
);
expect
(
listTwo
.
issues
.
length
).
toBe
(
1
);
done
();
},
0
);
});
it
(
'
moves issue to top of another list
'
,
(
done
)
=>
{
it
(
'
moves issue to top of another list
'
,
(
done
)
=>
{
const
listOne
=
gl
.
issueBoards
.
BoardsStore
.
addList
(
listObj
);
const
listOne
=
gl
.
issueBoards
.
BoardsStore
.
addList
(
listObj
);
const
listTwo
=
gl
.
issueBoards
.
BoardsStore
.
addList
(
listObjDuplicate
);
const
listTwo
=
gl
.
issueBoards
.
BoardsStore
.
addList
(
listObjDuplicate
);
...
...
spec/support/shared_examples/services/boards/issues_list_service.rb
View file @
5815c5b4
...
@@ -7,6 +7,16 @@ shared_examples 'issues list service' do
...
@@ -7,6 +7,16 @@ shared_examples 'issues list service' do
described_class
.
new
(
parent
,
user
,
params
).
execute
described_class
.
new
(
parent
,
user
,
params
).
execute
end
end
context
'#metadata'
do
it
'returns issues count for list'
do
params
=
{
board_id:
board
.
id
,
id:
list1
.
id
}
metadata
=
described_class
.
new
(
parent
,
user
,
params
).
metadata
expect
(
metadata
[
:size
]).
to
eq
(
3
)
end
end
context
'issues are ordered by priority'
do
context
'issues are ordered by priority'
do
it
'returns opened issues when list_id is missing'
do
it
'returns opened issues when list_id is missing'
do
params
=
{
board_id:
board
.
id
}
params
=
{
board_id:
board
.
id
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment