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
8ed0267f
Commit
8ed0267f
authored
Jun 06, 2018
by
Luke Bennett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merge 18466 to EE
parent
a808713a
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
324 additions
and
283 deletions
+324
-283
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
+111
-116
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
+25
-16
app/views/projects/labels/index.html.haml
app/views/projects/labels/index.html.haml
+19
-15
app/views/shared/_label.html.haml
app/views/shared/_label.html.haml
+54
-81
app/views/shared/_label_row.html.haml
app/views/shared/_label_row.html.haml
+13
-20
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 @
8ed0267f
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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -811,3 +811,5 @@ $modal-body-height: 134px;
Prometheus
*/
$prometheus-table-row-highlight-color
:
$theme-gray-100
;
$priority-label-empty-state-width
:
114px
;
app/assets/stylesheets/pages/labels.scss
View file @
8ed0267f
...
...
@@ -57,67 +57,6 @@
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
;
line-height
:
16px
;
...
...
@@ -133,14 +72,20 @@
}
.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
;
margin-bottom
:
5px
;
display
:
flex
;
justify-content
:
space-between
;
padding
:
8px
8px
8px
$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
;
...
...
@@ -149,9 +94,6 @@
cursor
:
-
webkit-grabbing
;
cursor
:
-
moz-grabbing
;
}
&
.sortable-ghost
{
opacity
:
0
.3
;
}
}
...
...
@@ -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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
-
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
-
if
can?
(
current_user
,
:admin_label
,
@group
)
=
link_to
"New label"
,
new_group_label_path
(
@group
),
class:
"btn btn-new"
=
link_to
_
(
'New label'
),
new_group_label_path
(
@group
),
class:
"btn btn-new"
.labels
-
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
}
-
if
can_admin_label
=
_
(
'Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.'
)
.labels-container.prepend-top-5
.other-labels
-
if
@labels
.
present?
%h5
Labels
%ul
.content-list.manage-labels-list.js-other-labels
=
render
partial:
'shared/label'
,
subject:
@group
,
collection:
@labels
,
as: :label
=
render
partial:
'shared/label'
,
subject:
@group
,
collection:
@labels
,
as: :label
,
locals:
{
use_label_priority:
true
}
=
paginate
@labels
,
theme:
'gitlab'
-
else
.nothing-here-block
=
_
(
"No labels created yet."
)
-
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/projects/labels/index.html.haml
View file @
8ed0267f
-
@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?}"
}
%h5
=
_
(
'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?}"
}
=
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 @
8ed0267f
-
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?
:
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
=
render
"shared/label_row"
,
label:
label
,
subject:
subject
,
force_priority:
force_priority
.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
-
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
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'
,
%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
,
...
...
@@ -65,34 +42,30 @@
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'
)
=
_
(
'Promote to group label'
)
%li
%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'
)
%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
%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
%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
.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 @
8ed0267f
-
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
.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-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
-
if
show_label_epics_link
=
link_to
'Epics'
,
group_epics_path
(
@group
,
label_name
:[
label
.
name
])
·
-
if
show_label_issues_link
%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 @
8ed0267f
---
title
:
Label list page redesign
merge_request
:
18466
author
:
type
:
changed
spec/features/projects/labels/subscription_spec.rb
View file @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -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 @
8ed0267f
...
...
@@ -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
li
.
click_link
(
"Delete"
)
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
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