Commit fec2e27f authored by Jan Provaznik's avatar Jan Provaznik

[backend] backport of scoped labels

Scoped labels in EE require additional changes in CE code.
parent 97ab8539
...@@ -7,6 +7,9 @@ module IssuableActions ...@@ -7,6 +7,9 @@ module IssuableActions
included do included do
before_action :authorize_destroy_issuable!, only: :destroy before_action :authorize_destroy_issuable!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update before_action :authorize_admin_issuable!, only: :bulk_update
before_action only: :show do
push_frontend_feature_flag(:scoped_labels, default_enabled: true)
end
end end
def permitted_keys def permitted_keys
......
...@@ -46,7 +46,7 @@ module LabelsHelper ...@@ -46,7 +46,7 @@ module LabelsHelper
if block_given? if block_given?
link_to link, class: css_class, &block link_to link, class: css_class, &block
else else
link_to render_colored_label(label, tooltip: tooltip), link, class: css_class render_label(label, tooltip: tooltip, link: link, css: css_class)
end end
end end
...@@ -78,19 +78,33 @@ module LabelsHelper ...@@ -78,19 +78,33 @@ module LabelsHelper
end end
end end
def render_colored_label(label, label_suffix = '', tooltip: true) def render_label(label, tooltip: true, link: nil, css: nil)
# if scoped label is used then EE wraps label tag with scoped label
# doc link
html = render_colored_label(label, tooltip: tooltip)
html = link_to(html, link, class: css) if link
html
end
def render_colored_label(label, label_suffix: '', tooltip: true, title: nil)
text_color = text_color_for_bg(label.color) text_color = text_color_for_bg(label.color)
title ||= label_tooltip_title(label)
# Intentionally not using content_tag here so that this method can be called # Intentionally not using content_tag here so that this method can be called
# by LabelReferenceFilter # by LabelReferenceFilter
span = %(<span class="badge color-label #{"has-tooltip" if tooltip}" ) + span = %(<span class="badge color-label #{"has-tooltip" if tooltip}" ) +
%(style="background-color: #{label.color}; color: #{text_color}" ) + %(data-html="true" style="background-color: #{label.color}; color: #{text_color}" ) +
%(title="#{escape_once(label.description)}" data-container="body">) + %(title="#{escape_once(title)}" data-container="body">) +
%(#{escape_once(label.name)}#{label_suffix}</span>) %(#{escape_once(label.name)}#{label_suffix}</span>)
span.html_safe span.html_safe
end end
def label_tooltip_title(label)
label.description
end
def suggested_colors def suggested_colors
[ [
'#0033CC', '#0033CC',
...@@ -231,6 +245,31 @@ module LabelsHelper ...@@ -231,6 +245,31 @@ module LabelsHelper
labels.sort_by(&:title) labels.sort_by(&:title)
end end
def label_dropdown_data(project, opts = {})
{
toggle: "dropdown",
field_name: opts[:field_name] || "label_name[]",
show_no: "true",
show_any: "true",
project_id: project&.try(:id),
namespace_path: project&.try(:namespace)&.try(:full_path),
project_path: project&.try(:path)
}.merge(opts)
end
def sidebar_label_dropdown_data(issuable_type, issuable_sidebar)
label_dropdown_data(nil, {
default_label: "Labels",
field_name: "#{issuable_type}[label_names][]",
ability_name: issuable_type,
namespace_path: issuable_sidebar[:namespace_path],
project_path: issuable_sidebar[:project_path],
issue_update: issuable_sidebar[:issuable_json_path],
labels: issuable_sidebar[:project_labels_path],
display: 'static'
})
end
# Required for Banzai::Filter::LabelReferenceFilter # Required for Banzai::Filter::LabelReferenceFilter
module_function :render_colored_label, :text_color_for_bg, :escape_once module_function :render_colored_label, :text_color_for_bg, :escape_once, :label_tooltip_title
end end
...@@ -4,7 +4,7 @@ class GlobalLabel ...@@ -4,7 +4,7 @@ class GlobalLabel
attr_accessor :title, :labels attr_accessor :title, :labels
alias_attribute :name, :title alias_attribute :name, :title
delegate :color, :text_color, :description, to: :@first_label delegate :color, :text_color, :description, :scoped_label?, to: :@first_label
def for_display def for_display
@first_label @first_label
......
...@@ -107,12 +107,13 @@ class IssuableBaseService < BaseService ...@@ -107,12 +107,13 @@ class IssuableBaseService < BaseService
@labels_service ||= ::Labels::AvailableLabelsService.new(current_user, parent, params) @labels_service ||= ::Labels::AvailableLabelsService.new(current_user, parent, params)
end end
def process_label_ids(attributes, existing_label_ids: nil) def process_label_ids(attributes, existing_label_ids: nil, extra_label_ids: [])
label_ids = attributes.delete(:label_ids) label_ids = attributes.delete(:label_ids)
add_label_ids = attributes.delete(:add_label_ids) add_label_ids = attributes.delete(:add_label_ids)
remove_label_ids = attributes.delete(:remove_label_ids) remove_label_ids = attributes.delete(:remove_label_ids)
new_label_ids = existing_label_ids || label_ids || [] new_label_ids = existing_label_ids || label_ids || []
new_label_ids |= extra_label_ids
if add_label_ids.blank? && remove_label_ids.blank? if add_label_ids.blank? && remove_label_ids.blank?
new_label_ids = label_ids if label_ids new_label_ids = label_ids if label_ids
...@@ -147,7 +148,7 @@ class IssuableBaseService < BaseService ...@@ -147,7 +148,7 @@ class IssuableBaseService < BaseService
params.delete(:state_event) params.delete(:state_event)
params[:author] ||= current_user params[:author] ||= current_user
params[:label_ids] = issuable.label_ids.to_a + process_label_ids(params) params[:label_ids] = process_label_ids(params, extra_label_ids: issuable.label_ids.to_a)
issuable.assign_attributes(params) issuable.assign_attributes(params)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.modal-dialog .modal-dialog
.modal-content .modal-content
.modal-header .modal-header
%h3.page-title Delete #{render_colored_label(label, tooltip: false)} ? %h3.page-title Delete #{render_label(label, tooltip: false)} ?
%button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') } %button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
%span{ "aria-hidden": true } &times; %span{ "aria-hidden": true } &times;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
- if defined?(@project) - if defined?(@project)
= link_to_label(label, subject: @project, tooltip: false) = link_to_label(label, subject: @project, tooltip: false)
- else - else
= render_colored_label(label, tooltip: false) = render_label(label, tooltip: false)
.label-description .label-description
.append-right-default.prepend-left-default .append-right-default.prepend-left-default
- if label.description.present? - if label.description.present?
......
...@@ -21,13 +21,7 @@ ...@@ -21,13 +21,7 @@
%button.dropdown-menu-toggle.js-label-select.js-multiselect.js-issue-board-sidebar{ type: "button", %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-issue-board-sidebar{ type: "button",
":data-selected" => "selectedLabels", ":data-selected" => "selectedLabels",
":data-labels" => "issue.assignableLabelsEndpoint", ":data-labels" => "issue.assignableLabelsEndpoint",
data: { toggle: "dropdown", data: label_dropdown_data(@project, namespace_path: @namespace_path, field_name: "issue[label_names][]") }
field_name: "issue[label_names][]",
show_no: "true",
show_any: "true",
project_id: @project&.try(:id),
namespace_path: @namespace_path,
project_path: @project.try(:path) } }
%span.dropdown-toggle-text %span.dropdown-toggle-text
{{ labelDropdownTitle }} {{ labelDropdownTitle }}
= icon('chevron-down') = icon('chevron-down')
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- classes = local_assigns.fetch(:classes, []) - classes = local_assigns.fetch(:classes, [])
- selected = local_assigns.fetch(:selected, nil) - selected = local_assigns.fetch(:selected, nil)
- dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by label") - dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by label")
- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), labels: labels_filter_path_with_defaults, default_label: "Labels"} - dropdown_data = label_dropdown_data(@project, labels: labels_filter_path_with_defaults, default_label: "Labels")
- dropdown_data.merge!(data_options) - dropdown_data.merge!(data_options)
- label_name = local_assigns.fetch(:label_name, "Labels") - label_name = local_assigns.fetch(:label_name, "Labels")
- no_default_styles = local_assigns.fetch(:no_default_styles, false) - no_default_styles = local_assigns.fetch(:no_default_styles, false)
......
...@@ -105,10 +105,9 @@ ...@@ -105,10 +105,9 @@
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right' = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right'
.value.issuable-show-labels.dont-hide.hide-collapsed.qa-labels-block{ class: ("has-labels" if selected_labels.any?) } .value.issuable-show-labels.dont-hide.hide-collapsed.qa-labels-block{ class: ("has-labels" if selected_labels.any?) }
- if selected_labels.any? - if selected_labels.any?
- selected_labels.each do |label| - selected_labels.each do |label_hash|
= link_to sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label[:title]) do - label = Label.new(label_hash.slice(:color, :description, :title))
%span.badge.color-label.has-tooltip{ style: "background-color: #{label[:color]}; color: #{label[:text_color]}", title: label[:description], data: { container: "body" } } = render_label(label, link: sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label[:title]))
= label[:title]
- else - else
%span.no-value %span.no-value
= _('None') = _('None')
...@@ -116,7 +115,7 @@ ...@@ -116,7 +115,7 @@
- selected_labels.each do |label| - selected_labels.each do |label|
= hidden_field_tag "#{issuable_type}[label_names][]", label[:id], id: nil = hidden_field_tag "#{issuable_type}[label_names][]", label[:id], id: nil
.dropdown .dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable_type}[label_names][]", ability_name: issuable_type, show_no: "true", show_any: "true", namespace_path: issuable_sidebar[:namespace_path], project_path: issuable_sidebar[:project_path], issue_update: issuable_sidebar[:issuable_json_path], labels: issuable_sidebar[:project_labels_path], display: 'static' } } %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: sidebar_label_dropdown_data(issuable_type, issuable_sidebar) }
%span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) } %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) }
= multi_label_name(selected_labels, "Labels") = multi_label_name(selected_labels, "Labels")
= icon('chevron-down', 'aria-hidden': 'true') = icon('chevron-down', 'aria-hidden': 'true')
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
.form-group.row .form-group.row
= f.label :title, class: 'col-form-label col-sm-2' = f.label :title, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= f.text_field :title, class: "form-control qa-label-title", required: true, autofocus: true = f.text_field :title, class: "form-control js-label-title qa-label-title", required: true, autofocus: true
= render_if_exists 'shared/labels/create_label_help_text'
.form-group.row .form-group.row
= f.label :description, class: 'col-form-label col-sm-2' = f.label :description, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
- labels.each do |label| - labels.each do |label|
= link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' }) do = link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' }) do
- render_colored_label(label) - render_label(label)
%span.assignee-icon %span.assignee-icon
- assignees.each do |assignee| - assignees.each do |assignee|
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
%li.is-not-draggable %li.is-not-draggable
%span.label-row %span.label-row
%span.label-name %span.label-name
= link_to milestones_label_path(options) do = render_label(label, tooltip: false, link: milestones_label_path(options))
- render_colored_label(label, tooltip: false)
%span.prepend-description-left %span.prepend-description-left
= markdown_field(label, :description) = markdown_field(label, :description)
......
...@@ -195,15 +195,21 @@ module Banzai ...@@ -195,15 +195,21 @@ module Banzai
content = link_content || object_link_text(object, matches) content = link_content || object_link_text(object, matches)
%(<a href="#{url}" #{data} link = %(<a href="#{url}" #{data}
title="#{escape_once(title)}" title="#{escape_once(title)}"
class="#{klass}">#{content}</a>) class="#{klass}">#{content}</a>)
wrap_link(link, object)
else else
match match
end end
end end
end end
def wrap_link(link, object)
link
end
def data_attributes_for(text, parent, object, link_content: false, link_reference: false) def data_attributes_for(text, parent, object, link_content: false, link_reference: false)
object_parent_type = parent.is_a?(Group) ? :group : :project object_parent_type = parent.is_a?(Group) ? :group : :project
......
...@@ -91,7 +91,11 @@ module Banzai ...@@ -91,7 +91,11 @@ module Banzai
label_suffix = " <i>in #{reference}</i>" if reference.present? label_suffix = " <i>in #{reference}</i>" if reference.present?
end end
LabelsHelper.render_colored_label(object, label_suffix) LabelsHelper.render_colored_label(object, label_suffix: label_suffix, title: tooltip_title(object))
end
def tooltip_title(label)
nil
end end
def full_path_ref?(matches) def full_path_ref?(matches)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment