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
3d6f8ed2
Commit
3d6f8ed2
authored
Jun 07, 2018
by
Rémy Coutable
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master' into ce-to-ee-2018-06-07
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parents
bea67568
be874b29
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
336 additions
and
289 deletions
+336
-289
app/assets/javascripts/group_label_subscription.js
app/assets/javascripts/group_label_subscription.js
+17
-1
app/assets/javascripts/label_manager.js
app/assets/javascripts/label_manager.js
+14
-1
app/assets/javascripts/project_label_subscription.js
app/assets/javascripts/project_label_subscription.js
+22
-6
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/framework/variables.scss
+2
-0
app/assets/stylesheets/pages/labels.scss
app/assets/stylesheets/pages/labels.scss
+112
-117
app/controllers/groups/labels_controller.rb
app/controllers/groups/labels_controller.rb
+13
-10
app/helpers/labels_helper.rb
app/helpers/labels_helper.rb
+8
-0
app/models/label.rb
app/models/label.rb
+4
-0
app/views/groups/labels/index.html.haml
app/views/groups/labels/index.html.haml
+23
-16
app/views/projects/labels/index.html.haml
app/views/projects/labels/index.html.haml
+25
-15
app/views/shared/_label.html.haml
app/views/shared/_label.html.haml
+55
-82
app/views/shared/_label_row.html.haml
app/views/shared/_label_row.html.haml
+19
-24
changelogs/unreleased/39549-label-list-page-redesign-with-draggable-labels.yml
.../39549-label-list-page-redesign-with-draggable-labels.yml
+5
-0
spec/features/projects/labels/subscription_spec.rb
spec/features/projects/labels/subscription_spec.rb
+3
-3
spec/features/projects/labels/update_prioritization_spec.rb
spec/features/projects/labels/update_prioritization_spec.rb
+4
-4
spec/features/projects/labels/user_removes_labels_spec.rb
spec/features/projects/labels/user_removes_labels_spec.rb
+10
-10
No files found.
app/assets/javascripts/group_label_subscription.js
View file @
3d6f8ed2
import
$
from
'
jquery
'
;
import
{
__
}
from
'
~/locale
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
flash
from
'
./flash
'
;
import
{
__
}
from
'
./locale
'
;
const
tooltipTitles
=
{
group
:
__
(
'
Unsubscribe at group level
'
),
project
:
__
(
'
Unsubscribe at project level
'
),
};
export
default
class
GroupLabelSubscription
{
constructor
(
container
)
{
...
...
@@ -35,6 +40,7 @@ export default class GroupLabelSubscription {
this
.
$unsubscribeButtons
.
attr
(
'
data-url
'
,
url
);
axios
.
post
(
url
)
.
then
(()
=>
GroupLabelSubscription
.
setNewTooltip
(
$btn
))
.
then
(()
=>
this
.
toggleSubscriptionButtons
())
.
catch
(()
=>
flash
(
__
(
'
There was an error when subscribing to this label.
'
)));
}
...
...
@@ -44,4 +50,14 @@ export default class GroupLabelSubscription {
this
.
$subscribeButtons
.
toggleClass
(
'
hidden
'
);
this
.
$unsubscribeButtons
.
toggleClass
(
'
hidden
'
);
}
static
setNewTooltip
(
$button
)
{
if
(
!
$button
.
hasClass
(
'
js-subscribe-button
'
))
return
;
const
type
=
$button
.
hasClass
(
'
js-group-level
'
)
?
'
group
'
:
'
project
'
;
const
newTitle
=
tooltipTitles
[
type
];
$
(
'
.js-unsubscribe-button
'
,
$button
.
closest
(
'
.label-actions-list
'
))
.
tooltip
(
'
hide
'
).
attr
(
'
title
'
,
newTitle
).
tooltip
(
'
_fixTitle
'
);
}
}
app/assets/javascripts/label_manager.js
View file @
3d6f8ed2
...
...
@@ -13,6 +13,7 @@ export default class LabelManager {
this
.
otherLabels
=
otherLabels
||
$
(
'
.js-other-labels
'
);
this
.
errorMessage
=
'
Unable to update label prioritization at this time
'
;
this
.
emptyState
=
document
.
querySelector
(
'
#js-priority-labels-empty-state
'
);
this
.
$badgeItemTemplate
=
$
(
'
#js-badge-item-template
'
);
this
.
sortable
=
Sortable
.
create
(
this
.
prioritizedLabels
.
get
(
0
),
{
filter
:
'
.empty-message
'
,
forceFallback
:
true
,
...
...
@@ -63,7 +64,11 @@ export default class LabelManager {
$target
=
this
.
otherLabels
;
$from
=
this
.
prioritizedLabels
;
}
$label
.
detach
().
appendTo
(
$target
);
const
$detachedLabel
=
$label
.
detach
();
this
.
toggleLabelPriorityBadge
(
$detachedLabel
,
action
);
$detachedLabel
.
appendTo
(
$target
);
if
(
$from
.
find
(
'
li
'
).
length
)
{
$from
.
find
(
'
.empty-message
'
).
removeClass
(
'
hidden
'
);
}
...
...
@@ -88,6 +93,14 @@ export default class LabelManager {
}
}
toggleLabelPriorityBadge
(
$label
,
action
)
{
if
(
action
===
'
remove
'
)
{
$
(
'
.js-priority-badge
'
,
$label
).
remove
();
}
else
{
$
(
'
.label-links
'
,
$label
).
append
(
this
.
$badgeItemTemplate
.
clone
().
html
());
}
}
onPrioritySortUpdate
()
{
this
.
savePrioritySort
()
.
catch
(()
=>
flash
(
this
.
errorMessage
));
...
...
app/assets/javascripts/project_label_subscription.js
View file @
3d6f8ed2
...
...
@@ -3,6 +3,17 @@ import { __ } from './locale';
import
axios
from
'
./lib/utils/axios_utils
'
;
import
flash
from
'
./flash
'
;
const
tooltipTitles
=
{
group
:
{
subscribed
:
__
(
'
Unsubscribe at group level
'
),
unsubscribed
:
__
(
'
Subscribe at group level
'
),
},
project
:
{
subscribed
:
__
(
'
Unsubscribe at project level
'
),
unsubscribed
:
__
(
'
Subscribe at project level
'
),
},
};
export
default
class
ProjectLabelSubscription
{
constructor
(
container
)
{
this
.
$container
=
$
(
container
);
...
...
@@ -15,12 +26,10 @@ export default class ProjectLabelSubscription {
event
.
preventDefault
();
const
$btn
=
$
(
event
.
currentTarget
);
const
$span
=
$btn
.
find
(
'
span
'
);
const
url
=
$btn
.
attr
(
'
data-url
'
);
const
oldStatus
=
$btn
.
attr
(
'
data-status
'
);
$btn
.
addClass
(
'
disabled
'
);
$span
.
toggleClass
(
'
hidden
'
);
axios
.
post
(
url
).
then
(()
=>
{
let
newStatus
;
...
...
@@ -32,21 +41,28 @@ export default class ProjectLabelSubscription {
[
newStatus
,
newAction
]
=
[
'
unsubscribed
'
,
'
Subscribe
'
];
}
$span
.
toggleClass
(
'
hidden
'
);
$btn
.
removeClass
(
'
disabled
'
);
this
.
$buttons
.
attr
(
'
data-status
'
,
newStatus
);
this
.
$buttons
.
find
(
'
> span
'
).
text
(
newAction
);
this
.
$buttons
.
map
((
button
)
=>
{
this
.
$buttons
.
map
((
i
,
button
)
=>
{
const
$button
=
$
(
button
);
const
originalTitle
=
$button
.
attr
(
'
data-original-title
'
);
if
(
$button
.
attr
(
'
data-original-title
'
)
)
{
$button
.
tooltip
(
'
hide
'
).
attr
(
'
data-original-title
'
,
newAction
).
tooltip
(
'
_fixTitle
'
);
if
(
originalTitle
)
{
ProjectLabelSubscription
.
setNewTitle
(
$button
,
originalTitle
,
newStatus
,
newAction
);
}
return
button
;
});
}).
catch
(()
=>
flash
(
__
(
'
There was an error subscribing to this label.
'
)));
}
static
setNewTitle
(
$button
,
originalTitle
,
newStatus
)
{
const
type
=
/group/
.
test
(
originalTitle
)
?
'
group
'
:
'
project
'
;
const
newTitle
=
tooltipTitles
[
type
][
newStatus
];
$button
.
attr
(
'
title
'
,
newTitle
).
tooltip
(
'
_fixTitle
'
);
}
}
app/assets/stylesheets/framework/variables.scss
View file @
3d6f8ed2
...
...
@@ -844,3 +844,5 @@ $modal-border-color: #e9ecef;
Prometheus
*/
$prometheus-table-row-highlight-color
:
$theme-gray-100
;
$priority-label-empty-state-width
:
114px
;
app/assets/stylesheets/pages/labels.scss
View file @
3d6f8ed2
...
...
@@ -57,69 +57,8 @@
border-bottom-left-radius
:
$border-radius-base
;
}
.label-row
{
.label-name
{
display
:
inline-block
;
margin-bottom
:
10px
;
@include
media-breakpoint-up
(
sm
)
{
width
:
200px
;
margin-left
:
$gl-padding
*
2
;
margin-bottom
:
0
;
}
.badge
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
max-width
:
100%
;
}
}
.label-type
{
display
:
block
;
margin-bottom
:
10px
;
margin-left
:
50px
;
@include
media-breakpoint-up
(
sm
)
{
display
:
inline-block
;
width
:
100px
;
margin-left
:
10px
;
margin-bottom
:
0
;
vertical-align
:
top
;
}
}
.label-description
{
display
:
block
;
margin-bottom
:
10px
;
.description-text
{
margin-bottom
:
$gl-padding
;
}
a
{
color
:
$blue-600
;
}
@include
media-breakpoint-up
(
sm
)
{
display
:
inline-block
;
max-width
:
50%
;
margin-left
:
10px
;
margin-bottom
:
0
;
vertical-align
:
top
;
}
}
.badge
{
padding
:
4px
$grid-size
;
font-size
:
$label-font-size
;
position
:
relative
;
top
:
(
$grid-size
/
2
);
}
}
.color-label
{
padding
:
0
$grid-size
;
padding
:
$gl-padding-4
$grid-size
;
line-height
:
16px
;
border-radius
:
$label-border-radius
;
color
:
$white-light
;
...
...
@@ -133,26 +72,29 @@
}
.manage-labels-list
{
@media
(
min-width
:
map-get
(
$grid-breakpoints
,
md
))
{
&
.content-list
li
{
padding
:
$gl-padding
0
;
}
}
>
li
:not
(
.empty-message
)
:not
(
.is-not-draggable
)
{
background-color
:
$white-light
;
cursor
:
move
;
cursor
:
-
webkit-grab
;
cursor
:
-
moz-grab
;
&
:active
{
cursor
:
-
webkit-grabbing
;
cursor
:
-
moz-grabbing
;
}
margin-bottom
:
5px
;
display
:
flex
;
justify-content
:
space-between
;
padding
:
$gl-padding
;
border-radius
:
$border-radius-default
;
&
.sortable-ghost
{
opacity
:
0
.3
;
}
.prioritized-labels
&
{
box-shadow
:
0
1px
2px
$issue-boards-card-shadow
;
cursor
:
move
;
cursor
:
-
webkit-grab
;
cursor
:
-
moz-grab
;
&
:active
{
cursor
:
-
webkit-grabbing
;
cursor
:
-
moz-grabbing
;
}
}
}
.btn-action
{
...
...
@@ -170,27 +112,6 @@
}
}
}
.dropdown
{
@include
media-breakpoint-up
(
sm
)
{
float
:
right
;
}
}
@include
media-breakpoint-down
(
xs
)
{
.dropdown-menu
{
min-width
:
100%
;
}
}
}
.draggable-handler
{
display
:
inline-block
;
vertical-align
:
top
;
margin
:
5px
0
;
opacity
:
0
;
transition
:
opacity
.3s
;
color
:
$gray-darkest
;
}
.prioritized-labels
{
...
...
@@ -215,22 +136,6 @@
}
}
.toggle-priority
{
display
:
inline-block
;
vertical-align
:
top
;
button
{
border-color
:
transparent
;
padding
:
5px
8px
;
vertical-align
:
top
;
font-size
:
14px
;
&
:hover
{
border-color
:
transparent
;
}
}
}
.filtered-labels
{
font-size
:
0
;
padding
:
12px
16px
;
...
...
@@ -284,10 +189,8 @@
}
.label-subscribe-button
{
@media
(
min-width
:
map-get
(
$grid-breakpoints
,
md
))
{
min-width
:
105px
;
margin-left
:
$gl-padding
;
}
width
:
105px
;
font-weight
:
200
;
.label-subscribe-button-icon
{
&
[
disabled
]
{
...
...
@@ -324,3 +227,95 @@
font-size
:
$label-font-size
;
}
}
.labels-container
{
background-color
:
$gray-light
;
border-radius
:
$border-radius-default
;
padding
:
$gl-padding
$gl-padding-8
;
}
.label-actions-list
{
list-style
:
none
;
flex-shrink
:
0
;
padding
:
0
;
}
.label-badge
{
color
:
$theme-gray-900
;
font-weight
:
$gl-font-weight-normal
;
padding
:
$gl-padding-4
$gl-padding-8
;
border-radius
:
$border-radius-default
;
font-size
:
$label-font-size
;
}
.label-badge-blue
{
background-color
:
$theme-blue-100
;
}
.label-badge-gray
{
background-color
:
$theme-gray-100
;
}
.label-links
{
list-style
:
none
;
padding
:
0
;
white-space
:
nowrap
;
}
.label-link-item
{
padding
:
0
;
}
.label-list-item
{
.
content-list
&
:
:
before
,
.
content-list
&::
after
{
content
:
none
;
}
.label-name
{
width
:
150px
;
flex-shrink
:
0
;
.label
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
max-width
:
100%
;
}
}
.label-description
{
flex-grow
:
1
;
a
{
color
:
$blue-600
;
}
}
.label
{
padding
:
4px
$grid-size
;
font-size
:
$label-font-size
;
position
:
relative
;
top
:
$gl-padding-4
;
}
.label-action
{
color
:
$theme-gray-800
;
cursor
:
pointer
;
svg
{
fill
:
$theme-gray-800
;
}
&
:hover
{
color
:
$blue-600
;
svg
{
fill
:
$blue-600
;
}
}
}
}
.priority-labels-empty-state
.svg-content
img
{
max-width
:
$priority-label-empty-state-width
;
}
app/controllers/groups/labels_controller.rb
View file @
3d6f8ed2
...
...
@@ -2,6 +2,7 @@ class Groups::LabelsController < Groups::ApplicationController
include
ToggleSubscriptionAction
before_action
:label
,
only:
[
:edit
,
:update
,
:destroy
]
before_action
:available_labels
,
only:
[
:index
]
before_action
:authorize_admin_labels!
,
only:
[
:new
,
:create
,
:edit
,
:update
,
:destroy
]
before_action
:save_previous_label_path
,
only:
[
:edit
]
...
...
@@ -12,17 +13,8 @@ class Groups::LabelsController < Groups::ApplicationController
format
.
html
do
@labels
=
@group
.
labels
.
page
(
params
[
:page
])
end
format
.
json
do
available_labels
=
LabelsFinder
.
new
(
current_user
,
group_id:
@group
.
id
,
only_group_labels:
params
[
:only_group_labels
],
include_ancestor_groups:
params
[
:include_ancestor_groups
],
include_descendant_groups:
params
[
:include_descendant_groups
]
).
execute
render
json:
LabelSerializer
.
new
.
represent_appearance
(
available_labels
)
render
json:
LabelSerializer
.
new
.
represent_appearance
(
@available_labels
)
end
end
end
...
...
@@ -113,4 +105,15 @@ class Groups::LabelsController < Groups::ApplicationController
def
save_previous_label_path
session
[
:previous_labels_path
]
=
URI
(
request
.
referer
||
''
).
path
end
def
available_labels
@available_labels
||=
LabelsFinder
.
new
(
current_user
,
group_id:
@group
.
id
,
only_group_labels:
params
[
:only_group_labels
],
include_ancestor_groups:
params
[
:include_ancestor_groups
],
include_descendant_groups:
params
[
:include_descendant_groups
]
).
execute
end
end
app/helpers/labels_helper.rb
View file @
3d6f8ed2
...
...
@@ -211,6 +211,14 @@ module LabelsHelper
end
end
def
label_status_tooltip
(
label
,
status
)
type
=
label
.
is_a?
(
ProjectLabel
)
?
'project'
:
'group'
level
=
status
.
unsubscribed?
?
type
:
status
.
sub
(
'-level'
,
''
)
action
=
status
.
unsubscribed?
?
'Subscribe'
:
'Unsubscribe'
"
#{
action
}
at
#{
level
}
level"
end
# Required for Banzai::Filter::LabelReferenceFilter
module_function
:render_colored_label
,
:text_color_for_bg
,
:escape_once
end
app/models/label.rb
View file @
3d6f8ed2
...
...
@@ -137,6 +137,10 @@ class Label < ActiveRecord::Base
priority
.
try
(
:priority
)
end
def
priority?
priorities
.
present?
end
def
template?
template
end
...
...
app/views/groups/labels/index.html.haml
View file @
3d6f8ed2
-
page_title
'Labels'
-
can_admin_label
=
can?
(
current_user
,
:admin_label
,
@group
)
-
issuables
=
[
'issues'
,
'merge requests'
]
+
(
@group
&
.
feature_available?
(
:epics
)
?
[
'epics'
]
:
[])
.top-area.adjust
.nav-text
=
_
(
"Labels can be applied to %{features}. Group labels are available for any project within the group."
)
%
{
features:
issuables
.
to_sentence
}
-
if
can_admin_label
-
content_for
(
:header_content
)
do
.nav-controls
=
link_to
_
(
'New label'
),
new_group_label_path
(
@group
),
class:
"btn btn-new"
-
if
@labels
.
exists?
#promote-label-modal
%div
{
class:
container_class
}
.top-area.adjust
.nav-text
=
_
(
'Labels can be applied to %{features}. Group labels are available for any project within the group.'
)
%
{
features:
issuables
.
to_sentence
}
.nav-controls
-
if
can?
(
current_user
,
:admin_label
,
@group
)
=
link_to
"New label"
,
new_group_label_path
(
@group
),
class:
"btn btn-new"
.labels-container.prepend-top-5
.other-labels
%h5
Labels
%ul
.content-list.manage-labels-list.js-other-labels
=
render
partial:
'shared/label'
,
subject:
@group
,
collection:
@labels
,
as: :label
,
locals:
{
use_label_priority:
false
}
=
paginate
@labels
,
theme:
'gitlab'
-
else
=
render
'shared/empty_states/labels'
.labels
.other-labels
-
if
@labels
.
present?
%ul
.content-list.manage-labels-list.js-other-labels
=
render
partial:
'shared/label'
,
subject:
@group
,
collection:
@labels
,
as: :label
=
paginate
@labels
,
theme:
'gitlab'
-
else
.nothing-here-block
=
_
(
"No labels created yet."
)
%template
#js-badge-item-template
%li
.label-link-item.js-priority-badge.inline.prepend-left-10
.label-badge.label-badge-blue
=
_
(
'Prioritized label'
)
app/views/projects/labels/index.html.haml
View file @
3d6f8ed2
-
@no_container
=
true
-
page_title
"Labels"
-
hide_class
=
''
-
can_admin_label
=
can?
(
current_user
,
:admin_label
,
@project
)
-
hide_class
=
''
-
if
can_admin_label
-
content_for
(
:header_content
)
do
.nav-controls
=
link_to
_
(
'New label'
),
new_project_label_path
(
@project
),
class:
"btn btn-new"
-
if
@labels
.
exists?
||
@prioritized_labels
.
exists?
#promote-label-modal
%div
{
class:
container_class
}
.top-area.adjust
.nav-text
Labels can be applied to issues and merge requests.
=
_
(
'Labels can be applied to issues and merge requests.'
)
-
if
can_admin_label
Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.
=
_
(
'Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.'
)
-
if
can_admin_label
.nav-controls
=
link_to
new_project_label_path
(
@project
),
class:
"btn btn-new"
do
New label
.labels
.labels-container.prepend-top-5
-
if
can_admin_label
-# Only show it in the first page
-
hide
=
@available_labels
.
empty?
||
(
params
[
:page
].
present?
&&
params
[
:page
]
!=
'1'
)
.prioritized-labels
{
class:
(
'hide'
if
hide
)
}
%h5
Prioritized Labels
%ul
.content-list.manage-labels-list.js-prioritized-labels
{
"data-url"
=>
set_priorities_project_labels_path
(
@project
)
}
#js-priority-labels-empty-state
{
class:
"#{'hidden' unless @prioritized_labels.empty?}"
}
<
<<<<<<
HEAD
%h5
.prepend-top-10
=
_
(
'Prioritized Labels'
)
.content-list.manage-labels-list.js-prioritized-labels
{
"data-url"
=>
set_priorities_project_labels_path
(
@project
)
}
#js-priority-labels-empty-state
.priority-labels-empty-state
{
class:
"#{'hidden' unless @prioritized_labels.empty?}"
}
==
=====
%h5
.prepend-top-10
=
_
(
'Prioritized Labels'
)
.content-list.manage-labels-list.js-prioritized-labels
{
"data-url"
=>
set_priorities_project_labels_path
(
@project
)
}
#js-priority-labels-empty-state
.priority-labels-empty-state
{
class:
"#{'hidden' unless @prioritized_labels.empty?}"
}
>
>>>>>> origin/master
=
render
'shared/empty_states/priority_labels'
-
if
@prioritized_labels
.
present?
=
render
partial:
'shared/label'
,
subject:
@project
,
collection:
@prioritized_labels
,
as: :label
=
render
partial:
'shared/label'
,
subject:
@project
,
collection:
@prioritized_labels
,
as: :label
,
locals:
{
force_priority:
true
}
-
if
@labels
.
present?
.other-labels
-
if
can_admin_label
%h5
{
class:
(
'hide'
if
hide
)
}
Other Labels
%ul
.content-list.manage-labels-list.js-other-labels
%h5
{
class:
(
'hide'
if
hide
)
}
=
_
(
'Other Labels'
)
.content-list.manage-labels-list.js-other-labels
=
render
partial:
'shared/label'
,
subject:
@project
,
collection:
@labels
,
as: :label
=
paginate
@labels
,
theme:
'gitlab'
-
else
=
render
'shared/empty_states/labels'
%template
#js-badge-item-template
%li
.label-link-item.js-priority-badge.inline.prepend-left-10
.label-badge.label-badge-blue
=
_
(
'Prioritized label'
)
app/views/shared/_label.html.haml
View file @
3d6f8ed2
-
label_css_id
=
dom_id
(
label
)
-
status
=
label_subscription_status
(
label
,
@project
).
inquiry
if
current_user
-
subject
=
local_assigns
[
:subject
]
-
use_label_priority
=
local_assigns
.
fetch
(
:use_label_priority
,
false
)
-
force_priority
=
local_assigns
.
fetch
(
:force_priority
,
use_label_priority
?
label
.
priority
.
present?
:
false
)
-
toggle_subscription_path
=
toggle_subscription_label_path
(
label
,
@project
)
if
current_user
-
show_label_epics_link
=
@group
&
.
feature_available?
(
:epics
)
-
show_label_merge_requests_link
=
show_label_issuables_link?
(
label
,
:merge_requests
,
project:
@project
)
-
show_label_issues_link
=
show_label_issuables_link?
(
label
,
:issues
,
project:
@project
)
-
tooltip_title
=
label_status_tooltip
(
label
,
status
)
if
status
%li
.label-list-item
{
id:
label_css_id
,
data:
{
id:
label
.
id
}
}
=
render
"shared/label_row"
,
label:
label
.d-inline-block.d-sm-none.dropdown
%button
.btn.btn-default.label-options-toggle
{
type:
'button'
,
data:
{
toggle:
"dropdown"
}
}
Options
=
icon
(
'caret-down'
)
.dropdown-menu.dropdown-menu-right
%ul
-
if
show_label_epics_link
%li
=
link_to
group_epics_path
(
@group
,
label_name
:[
label
.
name
])
do
View epics
-
if
show_label_merge_requests_link
%li
=
link_to_label
(
label
,
subject:
subject
,
type: :merge_request
)
do
View merge requests
-
if
show_label_issues_link
%li
=
link_to_label
(
label
,
subject:
subject
)
do
View open issues
-
if
current_user
%li
.label-subscription
-
if
can_subscribe_to_label_in_different_levels?
(
label
)
%a
.js-unsubscribe-button.label-subscribe-button
{
role:
'button'
,
href:
'#'
,
class:
(
'hidden'
if
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_path
}
}
%span
Unsubscribe
%a
.js-subscribe-button.label-subscribe-button
{
role:
'button'
,
href:
'#'
,
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_project_label_path
(
@project
,
label
)
}
}
%span
Subscribe at project level
%a
.js-subscribe-button.label-subscribe-button
{
role:
'button'
,
href:
'#'
,
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_group_label_path
(
label
.
group
,
label
)
}
}
%span
Subscribe at group level
-
else
%a
.js-subscribe-button.label-subscribe-button
{
role:
'button'
,
href:
'#'
,
data:
{
status:
status
,
url:
toggle_subscription_path
}
}
%span
=
label_subscription_toggle_button_text
(
label
,
@project
)
-
if
can?
(
current_user
,
:admin_label
,
label
)
%li
=
link_to
'Edit'
,
edit_label_path
(
label
)
%li
=
link_to
'Delete'
,
destroy_label_path
(
label
),
title:
'Delete'
,
method: :delete
,
data:
{
confirm:
'Remove this label? Are you sure?'
},
class:
'text-danger'
.float-right.d-none.d-sm-none.d-md-block
-
if
can?
(
current_user
,
:admin_label
,
label
)
-
if
label
.
is_a?
(
ProjectLabel
)
&&
label
.
project
.
group
&&
can?
(
current_user
,
:admin_label
,
label
.
project
.
group
)
%button
.js-promote-project-label-button.btn.btn-transparent.btn-action.has-tooltip
{
title:
_
(
'Promote to Group Label'
),
disabled:
true
,
type:
'button'
,
data:
{
url:
promote_project_label_path
(
label
.
project
,
label
),
label_title:
label
.
title
,
label_color:
label
.
color
,
label_text_color:
label
.
text_color
,
group_name:
label
.
project
.
group
.
name
,
target:
'#promote-label-modal'
,
container:
'body'
,
toggle:
'modal'
}
}
=
sprite_icon
(
'level-up'
)
=
link_to
edit_label_path
(
label
),
title:
"Edit"
,
class:
'btn btn-transparent btn-action'
,
data:
{
toggle:
"tooltip"
}
do
%span
.sr-only
Edit
=
sprite_icon
(
'pencil'
)
%span
{
data:
{
toggle:
'modal'
,
target:
"#modal-delete-label-#{label.id}"
}
}
=
link_to
"#"
,
title:
"Delete"
,
class:
'btn btn-transparent btn-action remove-row'
,
data:
{
toggle:
"tooltip"
}
do
%span
.sr-only
Delete
=
sprite_icon
(
'remove'
)
=
render
"shared/label_row"
,
label:
label
,
subject:
subject
,
force_priority:
force_priority
%ul
.label-actions-list
-
if
@project
%li
.inline
.label-badge.label-badge-gray
=
label
.
model_name
.
human
.
capitalize
-
if
can?
(
current_user
,
:admin_label
,
@project
)
%li
.inline.js-toggle-priority
{
data:
{
url:
remove_priority_project_label_path
(
@project
,
label
),
dom_id:
dom_id
(
label
),
type:
label
.
type
}
}
%button
.label-action.add-priority.btn.btn-transparent.has-tooltip
{
title:
_
(
'Prioritize'
),
type:
'button'
,
data:
{
placement:
'top'
},
aria_label:
_
(
'Prioritize label'
)
}
=
sprite_icon
(
'star-o'
)
%button
.label-action.remove-priority.btn.btn-transparent.has-tooltip
{
title:
_
(
'Remove priority'
),
type:
'button'
,
data:
{
placement:
'top'
},
aria_label:
_
(
'Deprioritize label'
)
}
=
sprite_icon
(
'star'
)
%li
.inline
=
link_to
edit_label_path
(
label
),
class:
'btn btn-transparent label-action'
,
aria_label:
'Edit label'
do
=
sprite_icon
(
'pencil'
)
%li
.inline
.dropdown
%button
{
type:
'button'
,
class:
'btn btn-transparent js-label-options-dropdown label-action'
,
data:
{
toggle:
'dropdown'
},
aria_label:
_
(
'Label actions dropdown'
)
}
=
sprite_icon
(
'ellipsis_v'
)
.dropdown-menu.dropdown-open-left
%ul
-
if
label
.
is_a?
(
ProjectLabel
)
&&
label
.
project
.
group
&&
can?
(
current_user
,
:admin_label
,
label
.
project
.
group
)
%li
%button
.js-promote-project-label-button.btn.btn-transparent.btn-action
{
disabled:
true
,
type:
'button'
,
data:
{
url:
promote_project_label_path
(
label
.
project
,
label
),
label_title:
label
.
title
,
label_color:
label
.
color
,
label_text_color:
label
.
text_color
,
group_name:
label
.
project
.
group
.
name
,
target:
'#promote-label-modal'
,
container:
'body'
,
toggle:
'modal'
}
}
=
_
(
'Promote to group label'
)
%li
%span
{
data:
{
toggle:
'modal'
,
target:
"#modal-delete-label-#{label.id}"
}
}
%button
.text-danger.remove-row
{
type:
'button'
}=
_
(
'Delete'
)
-
if
current_user
.label-subscription.inline
%li
.inline.label-subscription
-
if
can_subscribe_to_label_in_different_levels?
(
label
)
%button
.js-unsubscribe-button.label-subscribe-button.btn.btn-default
{
type:
'button'
,
class:
(
'hidden'
if
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_path
}
}
%span
Unsubscribe
=
icon
(
'spinner spin'
,
class:
'label-subscribe-button-loading'
)
%button
.js-unsubscribe-button.label-subscribe-button.btn.btn-default
{
class:
(
'hidden'
if
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_path
,
toggle:
'tooltip'
},
title:
tooltip_title
}
%span
=
_
(
'Unsubscribe'
)
.dropdown.dropdown-group-label
{
class:
(
'hidden'
unless
status
.
unsubscribed?
)
}
%button
.dropdown-menu-toggle
{
type:
'button'
,
'data-toggle'
=>
'dropdown'
}
%span
Subscribe
=
icon
(
'chevron-down'
)
%ul
.dropdown-menu
%li
%a
.js-subscribe-button
{
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_project_label_path
(
@project
,
label
)
}
}
Project level
%a
.js-subscribe-button
{
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
url:
toggle_subscription_group_label_path
(
label
.
group
,
label
)
}
}
Group level
%button
.label-subscribe-button.btn.btn-default
{
data:
{
toggle:
'dropdown'
}
}
%span
=
_
(
'Subscribe'
)
=
sprite_icon
(
'chevron-down'
)
.dropdown-menu.dropdown-open-left
%ul
%li
%button
.js-subscribe-button.label-subscribe-button.btn.btn-default
{
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
status:
status
,
url:
toggle_subscription_project_label_path
(
@project
,
label
)
}
}
%span
=
_
(
'Subscribe at project level'
)
%li
%button
.js-subscribe-button.js-group-level.label-subscribe-button.btn.btn-default
{
class:
(
'hidden'
unless
status
.
unsubscribed?
),
data:
{
status:
status
,
url:
toggle_subscription_group_label_path
(
label
.
group
,
label
)
}
}
%span
=
_
(
'Subscribe at group level'
)
-
else
%button
.js-subscribe-button.label-subscribe-button.btn.btn-default
{
type:
'button'
,
data:
{
status:
status
,
url:
toggle_subscription_path
}
}
%button
.js-subscribe-button.label-subscribe-button.btn.btn-default
{
data:
{
status:
status
,
url:
toggle_subscription_path
,
toggle:
'tooltip'
},
title:
tooltip_title
}
%span
=
label_subscription_toggle_button_text
(
label
,
@project
)
=
icon
(
'spinner spin'
,
class:
'label-subscribe-button-loading'
)
=
render
'shared/delete_label_modal'
,
label:
label
app/views/shared/_label_row.html.haml
View file @
3d6f8ed2
-
subject
=
local_assigns
[
:subject
]
-
force_priority
=
local_assigns
.
fetch
(
:force_priority
,
false
)
-
show_label_epics_link
=
@group
&
.
feature_available?
(
:epics
)
-
show_label_issues_link
=
show_label_issuables_link?
(
label
,
:issues
,
project:
@project
)
-
show_label_merge_requests_link
=
show_label_issuables_link?
(
label
,
:merge_requests
,
project:
@project
)
%span
.label-row
-
if
can?
(
current_user
,
:admin_label
,
@project
)
.draggable-handler
=
icon
(
'bars'
)
.js-toggle-priority.toggle-priority
{
data:
{
url:
remove_priority_project_label_path
(
@project
,
label
),
dom_id:
dom_id
(
label
),
type:
label
.
type
}
}
%button
.add-priority.btn.has-tooltip
{
title:
'Prioritize'
,
type:
'button'
,
:'data-placement'
=>
'top'
}
=
icon
(
'star-o'
)
%button
.remove-priority.btn.has-tooltip
{
title:
'Remove priority'
,
type:
'button'
,
:'data-placement'
=>
'top'
}
=
icon
(
'star'
)
%span
.label-name
=
link_to_label
(
label
,
subject:
@project
,
tooltip:
false
)
-
if
defined?
(
@project
)
&&
@project
.
group
.
present?
%span
.label-type
=
label
.
model_name
.
human
.
titleize
%span
.label-description
.label-name
=
link_to_label
(
label
,
subject:
@project
,
tooltip:
false
)
.label-description
.append-right-default.prepend-left-default
-
if
label
.
description
.
present?
.description-text
.description-text
.append-bottom-10
=
markdown_field
(
label
,
:description
)
.d-none.d-sm-none.d-md-block
%ul
.label-links
-
if
show_label_epics_link
=
link_to
'Epics'
,
group_epics_path
(
@group
,
label_name
:[
label
.
name
])
·
%li
.label-link-item.inline
=
link_to
'Epics'
,
group_epics_path
(
@group
,
label_name
:[
label
.
name
])
·
-
if
show_label_issues_link
=
link_to_label
(
label
,
subject:
subject
)
{
'Issues'
}
%li
.label-link-item.inline
=
link_to_label
(
label
,
subject:
subject
)
{
'Issues'
}
·
-
if
show_label_merge_requests_link
·
=
link_to_label
(
label
,
subject:
subject
,
type: :merge_request
)
{
'Merge requests'
}
%li
.label-link-item.inline
=
link_to_label
(
label
,
subject:
subject
,
type: :merge_request
)
{
_
(
'Merge requests'
)
}
·
-
if
force_priority
%li
.label-link-item.js-priority-badge.inline.prepend-left-10
.label-badge.label-badge-blue
=
_
(
'Prioritized label'
)
changelogs/unreleased/39549-label-list-page-redesign-with-draggable-labels.yml
0 → 100644
View file @
3d6f8ed2
---
title
:
Label list page redesign
merge_request
:
18466
author
:
type
:
changed
spec/features/projects/labels/subscription_spec.rb
View file @
3d6f8ed2
...
...
@@ -36,7 +36,7 @@ feature 'Labels subscription' do
within
"#group_label_
#{
feature
.
id
}
"
do
expect
(
page
).
not_to
have_button
'Unsubscribe'
click_link_on_dropdown
(
'
G
roup level'
)
click_link_on_dropdown
(
'
Subscribe at g
roup level'
)
expect
(
page
).
not_to
have_selector
(
'.dropdown-group-label'
)
expect
(
page
).
to
have_button
'Unsubscribe'
...
...
@@ -45,7 +45,7 @@ feature 'Labels subscription' do
expect
(
page
).
to
have_selector
(
'.dropdown-group-label'
)
click_link_on_dropdown
(
'
P
roject level'
)
click_link_on_dropdown
(
'
Subscribe at p
roject level'
)
expect
(
page
).
not_to
have_selector
(
'.dropdown-group-label'
)
expect
(
page
).
to
have_button
'Unsubscribe'
...
...
@@ -68,7 +68,7 @@ feature 'Labels subscription' do
find
(
'.dropdown-group-label'
).
click
page
.
within
(
'.dropdown-group-label'
)
do
find
(
'
a
.js-subscribe-button'
,
text:
text
).
click
find
(
'.js-subscribe-button'
,
text:
text
).
click
end
end
end
spec/features/projects/labels/update_prioritization_spec.rb
View file @
3d6f8ed2
...
...
@@ -102,16 +102,16 @@ feature 'Prioritize labels' do
drag_to
(
selector:
'.label-list-item'
,
from_index:
1
,
to_index:
2
)
page
.
within
(
'.prioritized-labels'
)
do
expect
(
first
(
'
li
'
)).
to
have_content
(
'feature'
)
expect
(
page
.
all
(
'
li
'
).
last
).
to
have_content
(
'bug'
)
expect
(
first
(
'
.label-list-item
'
)).
to
have_content
(
'feature'
)
expect
(
page
.
all
(
'
.label-list-item
'
).
last
).
to
have_content
(
'bug'
)
end
refresh
wait_for_requests
page
.
within
(
'.prioritized-labels'
)
do
expect
(
first
(
'
li
'
)).
to
have_content
(
'feature'
)
expect
(
page
.
all
(
'
li
'
).
last
).
to
have_content
(
'bug'
)
expect
(
first
(
'
.label-list-item
'
)).
to
have_content
(
'feature'
)
expect
(
page
.
all
(
'
.label-list-item
'
).
last
).
to
have_content
(
'bug'
)
end
end
...
...
spec/features/projects/labels/user_removes_labels_spec.rb
View file @
3d6f8ed2
...
...
@@ -17,8 +17,9 @@ describe "User removes labels" do
end
it
"removes label"
do
page
.
within
(
".labels"
)
do
page
.
within
(
".
other-
labels"
)
do
page
.
first
(
".label-list-item"
)
do
first
(
'.js-label-options-dropdown'
).
click
first
(
".remove-row"
).
click
first
(
:link
,
"Delete label"
).
click
end
...
...
@@ -36,17 +37,16 @@ describe "User removes labels" do
end
it
"removes all labels"
do
page
.
within
(
".labels"
)
do
loop
do
li
=
page
.
first
(
".label-list-item"
)
break
unless
li
loop
do
li
=
page
.
first
(
".label-list-item"
)
break
unless
li
li
.
click_link
(
"Delete"
)
click_link
(
"Delete label"
)
end
expect
(
page
).
to
have_content
(
"Generate a default set of labels"
).
and
have_content
(
"New label"
)
li
.
find
(
'.js-label-options-dropdown'
).
click
li
.
click_button
(
"Delete"
)
click_link
(
"Delete label"
)
end
expect
(
page
).
to
have_content
(
"Generate a default set of labels"
).
and
have_content
(
"New label"
)
end
end
end
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