Commit a472c1bf authored by Grzegorz Bizon's avatar Grzegorz Bizon

Add support for cross project references for labels

parent dbc7bf7f
...@@ -51,7 +51,8 @@ class Label < ActiveRecord::Base ...@@ -51,7 +51,8 @@ class Label < ActiveRecord::Base
# Pattern used to extract label references from text # Pattern used to extract label references from text
def self.reference_pattern def self.reference_pattern
%r{ %r{
#{reference_prefix} (#{Project.reference_pattern})?
#{Regexp.escape(reference_prefix)}
(?: (?:
(?<label_id>\d+) | # Integer-based label ID, or (?<label_id>\d+) | # Integer-based label ID, or
(?<label_name> (?<label_name>
...@@ -62,6 +63,10 @@ class Label < ActiveRecord::Base ...@@ -62,6 +63,10 @@ class Label < ActiveRecord::Base
}x }x
end end
def self.link_reference_pattern
nil
end
# Returns the String necessary to reference this Label in Markdown # Returns the String necessary to reference this Label in Markdown
# #
# format - Symbol format to use (default: :id, optional: :name) # format - Symbol format to use (default: :id, optional: :name)
......
module Banzai module Banzai
module Filter module Filter
# HTML filter that replaces label references with links. # HTML filter that replaces label references with links.
class LabelReferenceFilter < ReferenceFilter class LabelReferenceFilter < AbstractReferenceFilter
# Public: Find label references in text def self.object_class
# Label
# LabelReferenceFilter.references_in(text) do |match, id, name|
# "<a href=...>#{Label.find(id)}</a>"
# end
#
# text - String text to search.
#
# Yields the String match, an optional Integer label ID, and an optional
# String label name.
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(Label.reference_pattern) do |match|
yield match, $~[:label_id].to_i, $~[:label_name]
end
end end
def self.referenced_by(node) def find_object(project, id)
{ label: LazyReference.new(Label, node.attr("data-label")) } project.labels.find(id)
end end
def call def self.references_in(text, pattern = Label.reference_pattern)
replace_text_nodes_matching(Label.reference_pattern) do |content| text.gsub(pattern) do |match|
label_link_filter(content) yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~
end
replace_link_nodes_with_href(Label.reference_pattern) do |link, text|
label_link_filter(link, link_text: text)
end end
end end
# Replace label references in text with links to the label specified. def self.referenced_by(node)
# { label: LazyReference.new(Label, node.attr("data-label")) }
# text - String text to replace references in. end
#
# Returns a String with label references replaced with links. All links
# have `gfm` and `gfm-label` class names attached for styling.
def label_link_filter(text, link_text: nil)
project = context[:project]
self.class.references_in(text) do |match, id, name|
params = label_params(id, name)
if label = project.labels.find_by(params)
url = url_for_label(project, label)
klass = reference_class(:label)
data = data_attribute(
original: link_text || match,
project: project.id,
label: label.id
)
text = link_text || render_colored_label(label) def references_in(text, pattern = Label.reference_pattern)
text.gsub(pattern) do |match|
project = project_from_ref($~[:project])
params = label_params($~[:label_id].to_i, $~[:label_name])
label = project.labels.find_by(params)
%(<a href="#{url}" #{data} if label
class="#{klass}">#{escape_once(text)}</a>) yield match, label.id, $~[:project], $~
else else
match match
end end
end end
end end
def url_for_label(project, label) def url_for_object(label, project)
h = Gitlab::Application.routes.url_helpers h = Gitlab::Application.routes.url_helpers
h.namespace_project_issues_url( project.namespace, project, label_name: label.name, h.namespace_project_issues_url(project.namespace, project, label_name: label.name,
only_path: context[:only_path]) only_path: context[:only_path])
end end
def render_colored_label(label) def object_link_text(object, _matches)
LabelsHelper.render_colored_label(label) LabelsHelper.render_colored_label(object)
end end
# Parameters to pass to `Label.find_by` based on the given arguments # Parameters to pass to `Label.find_by` based on the given arguments
......
...@@ -176,4 +176,23 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do ...@@ -176,4 +176,23 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
expect(result[:references][:label]).to eq [label] expect(result[:references][:label]).to eq [label]
end end
end end
describe 'cross project label references' do
let(:another_project) { create(:empty_project, :public) }
let(:label) { create(:label, project: another_project, color: '#00ff00') }
let(:reference) { label.to_reference(project) }
let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project issues page' do
expect(result.css('a').first.attr('href'))
.to eq urls.namespace_project_issues_url(another_project.namespace,
another_project,
label_name: label.name)
end
it 'has valid color' do
expect(result.css('a span').first.attr('style')).to match /background-color: #00ff00/
end
end
end end
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