Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-22 09:11:01 +00:00
parent c17064b66b
commit 2763994b8f
14 changed files with 282 additions and 93 deletions

View file

@ -17,7 +17,15 @@ export default class IssuableTemplateSelector extends TemplateSelector {
name: this.dropdown.data('selected'),
};
if (initialQuery.name) this.requestFile(initialQuery);
// Only use the default template if we don't have description data from autosave
if (!initialQuery.name && this.dropdown.data('default') && !this.editor.getValue().length) {
initialQuery.name = this.dropdown.data('default');
}
if (initialQuery.name) {
this.requestFile(initialQuery);
this.setToggleText(initialQuery.name);
}
$('.reset-template', this.dropdown.parent()).on('click', () => {
this.setInputValueToTemplateContent();
@ -53,10 +61,14 @@ export default class IssuableTemplateSelector extends TemplateSelector {
}
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text(__('Choose a template'));
this.setToggleText(__('Choose a template'));
this.previousSelectedIndex = null;
}
setToggleText(text) {
$('.dropdown-toggle-text', this.dropdown).text(text);
}
setSelectedIndex() {
this.previousSelectedIndex = this.dropdown.data('deprecatedJQueryDropdown').selectedIndex;
}

View file

@ -5,8 +5,12 @@ module IssuablesDescriptionTemplatesHelper
include GitlabRoutingHelper
def template_dropdown_tag(issuable, &block)
selected_template = selected_template(issuable)
title = selected_template || _('Choose a template')
template_names = template_names(issuable)
selected_template = selected_template_name(template_names)
default_template = default_template_name(template_names, issuable)
title = _('Choose a template')
options = {
toggle_class: 'js-issuable-selector',
title: title,
@ -17,6 +21,7 @@ module IssuablesDescriptionTemplatesHelper
data: issuable_templates(ref_project, issuable.to_ability_name),
field_name: 'issuable_template',
selected: selected_template,
default: default_template,
project_id: ref_project.id
}
}
@ -32,19 +37,19 @@ module IssuablesDescriptionTemplatesHelper
@template_types[project.id][issuable_type] ||= TemplateFinder.all_template_names(project, issuable_type.pluralize)
end
def selected_template(issuable)
all_templates = issuable_templates(ref_project, issuable.to_ability_name)
# Only local templates will be listed if licenses for inherited templates are not present
all_templates = all_templates.values.flatten.map { |tpl| tpl[:name] }.compact.uniq
template = all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] }
unless issuable.description.present?
template ||= all_templates.find { |tmpl_name| tmpl_name.casecmp?('default') }
def selected_template_name(template_names)
template_names.find { |tmpl_name| tmpl_name == params[:issuable_template] }
end
template
def default_template_name(template_names, issuable)
return if issuable.description.present? || issuable.persisted?
template_names.find { |tmpl_name| tmpl_name.casecmp?('default') }
end
def template_names(issuable)
# Only local templates will be listed if licenses for inherited templates are not present
issuable_templates(ref_project, issuable.to_ability_name).values.flatten.map { |tpl| tpl[:name] }.compact.uniq
end
def available_service_desk_templates_for(project)

View file

@ -5,9 +5,14 @@ module Todos
class DestroyedIssuableService
BATCH_SIZE = 100
# Since we are moving towards work items, in some instances we create todos with
# `target_type: WorkItem` in other instances we still create todos with `target_type: Issue`
# So when an issue/work item is deleted, we just make sure to delete todos for both target types
BOUND_TARGET_TYPES = %w(Issue WorkItem).freeze
def initialize(target_id, target_type)
@target_id = target_id
@target_type = target_type
@target_type = BOUND_TARGET_TYPES.include?(target_type) ? BOUND_TARGET_TYPES : target_type
end
def execute

View file

@ -7556,16 +7556,35 @@
wysiwyg: |-
<p>Multiple spaces</p>
07_01__gitlab_specific_markdown__footnotes__001:
canonical: ""
canonical: |
<p>
footnote reference tag
<sup>
<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
1
</a>
</sup>
</p>
<section data-footnotes>
<ol>
<li id="fn-fortytwo-42">
<p>
footnote text
<a href="#fnref-fortytwo-42" data-footnote-backref>
</a>
</p>
</li>
</ol>
</section>
static: |-
<p data-sourcepos="1:1-1:27" dir="auto">footnote reference tag <sup class="footnote-ref"><a href="#fn-1-9034" id="fnref-1-9034" data-footnote-ref>1</a></sup></p>
<p data-sourcepos="1:1-1:34" dir="auto">footnote reference tag <sup class="footnote-ref"><a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>1</a></sup></p>
<section data-footnotes class="footnotes">
<ol>
<li id="fn-1-9034">
<p data-sourcepos="3:7-3:19">footnote text <a href="#fnref-1-9034" data-footnote-backref aria-label="Back to content" class="footnote-backref"><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
<li id="fn-fortytwo-42">
<p data-sourcepos="3:14-3:26">footnote text <a href="#fnref-fortytwo-42" data-footnote-backref aria-label="Back to content" class="footnote-backref"><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
</li>
</ol>
</section>
wysiwyg: |-
<p>footnote reference tag <sup identifier="1">1</sup></p>
<p>footnote reference tag <sup identifier="fortytwo">fortytwo</sup></p>
<div node="footnoteDefinition(paragraph(&quot;footnote text&quot;))" htmlattributes="[object Object]"><p>footnote text</p></div>

View file

@ -2190,6 +2190,6 @@
06_15__inlines__textual_content__003: |
Multiple spaces
07_01__gitlab_specific_markdown__footnotes__001: |
footnote reference tag [^1]
footnote reference tag [^fortytwo]
[^1]: footnote text
[^fortytwo]: footnote text

View file

@ -19218,8 +19218,8 @@
{
"type": "footnoteReference",
"attrs": {
"identifier": "1",
"label": "1"
"identifier": "fortytwo",
"label": "fortytwo"
}
}
]
@ -19227,8 +19227,8 @@
{
"type": "footnoteDefinition",
"attrs": {
"identifier": "1",
"label": "1"
"identifier": "fortytwo",
"label": "fortytwo"
},
"content": [
{

View file

@ -14,7 +14,27 @@ See
[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
```````````````````````````````` example gitlab footnote
footnote reference tag [^1]
footnote reference tag [^fortytwo]
[^1]: footnote text
[^fortytwo]: footnote text
.
<p>
footnote reference tag
<sup>
<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
1
</a>
</sup>
</p>
<section data-footnotes>
<ol>
<li id="fn-fortytwo-42">
<p>
footnote text
<a href="#fnref-fortytwo-42" data-footnote-backref>
</a>
</p>
</li>
</ol>
</section>
````````````````````````````````

View file

@ -9616,9 +9616,29 @@ See
[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
```````````````````````````````` example gitlab footnote
footnote reference tag [^1]
footnote reference tag [^fortytwo]
[^1]: footnote text
[^fortytwo]: footnote text
.
<p>
footnote reference tag
<sup>
<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
1
</a>
</sup>
</p>
<section data-footnotes>
<ol>
<li id="fn-fortytwo-42">
<p>
footnote text
<a href="#fnref-fortytwo-42" data-footnote-backref>
</a>
</p>
</li>
</ol>
</section>
````````````````````````````````
<!-- END TESTS -->

View file

@ -29,6 +29,8 @@ module Glfm
def process(skip_static_and_wysiwyg: false)
output('Updating example snapshots...')
setup_environment
output('(Skipping static HTML generation)') if skip_static_and_wysiwyg
output("Reading #{GLFM_SPEC_TXT_PATH}...")
@ -47,6 +49,14 @@ module Glfm
private
def setup_environment
# Set 'GITLAB_TEST_FOOTNOTE_ID' in order to override random number generation in
# Banzai::Filter::FootnoteFilter#random_number, and thus avoid the need to
# perform normalization on the value. See:
# https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#normalization
ENV['GITLAB_TEST_FOOTNOTE_ID'] = '42'
end
def add_example_names(all_examples)
# NOTE: This method and the parse_examples method assume:
# 1. Section 2 is the first section which contains examples

View file

@ -90,6 +90,34 @@ RSpec.describe 'issuable templates', :js do
end
end
context 'user creates an issue with a default template from the repo' do
let(:template_content) { 'this is the default template' }
before do
project.repository.create_file(
user,
'.gitlab/issue_templates/default.md',
template_content,
message: 'added default issue template',
branch_name: 'master'
)
end
it 'does not overwrite autosaved description' do
visit new_project_issue_path project
wait_for_requests
assert_template # default template is loaded the first time
fill_in 'issue_description', with: 'my own description', fill_options: { clear: :backspace }
visit new_project_issue_path project
wait_for_requests
assert_template(expected_content: 'my own description')
end
end
context 'user creates a merge request using templates' do
let(:template_content) { 'this is a test "feature-proposal" template' }
let(:bug_template_content) { 'this is merge request bug template' }

View file

@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
describe '#issuable_templates' do
include_context 'project issuable templates context'
describe '#issuable_templates' do
let_it_be(:inherited_from) { nil }
let_it_be(:user) { create(:user) }
let_it_be(:parent_group, reload: true) { create(:group) }
@ -44,7 +44,7 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
end
end
describe '#selected_template' do
describe '#available_service_desk_templates_for' do
let_it_be(:project) { build(:project) }
before do
@ -72,40 +72,9 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
].to_json
expect(helper.available_service_desk_templates_for(@project)).to eq(value)
end
context 'when no issuable_template parameter or default template is present' do
it 'does not select a template' do
expect(helper.selected_template(project)).to be(nil)
end
end
context 'when an issuable_template parameter has been provided' do
before do
allow(helper).to receive(:params).and_return({ issuable_template: 'another_issue_template' })
end
it 'selects the issuable template' do
expect(helper.selected_template(project)).to eq('another_issue_template')
end
end
context 'when there is a default template' do
let(:templates) do
{
"" => [
{ name: "another_issue_template", id: "another_issue_template", project_id: project.id },
{ name: "default", id: "default", project_id: project.id }
]
}
end
it 'selects the default template' do
expect(helper.selected_template(project)).to eq('default')
end
end
end
context 'when there are not templates in the project' do
context 'when there are no templates in the project' do
let(:templates) { {} }
it 'returns empty array' do
@ -114,4 +83,92 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
end
end
end
describe '#selected_template_name' do
let(:template_names) { %w(another_issue_template custom_issue_template) }
context 'when no issuable_template parameter is provided' do
it 'does not select a template' do
expect(helper.selected_template_name(template_names)).to be_nil
end
end
context 'when an issuable_template parameter has been provided' do
before do
allow(helper).to receive(:params).and_return({ issuable_template: template_param_value })
end
context 'when param matches existing templates' do
let(:template_param_value) { 'another_issue_template' }
it 'returns the matching issuable template' do
expect(helper.selected_template_name(template_names)).to eq('another_issue_template')
end
end
context 'when param does not match any templates' do
let(:template_param_value) { 'non_matching_issue_template' }
it 'returns nil' do
expect(helper.selected_template_name(template_names)).to be_nil
end
end
end
end
describe '#default_template_name' do
context 'when a default template is available' do
let(:template_names) { %w(another_issue_template deFault) }
it 'returns the default template' do
issue = build(:issue)
expect(helper.default_template_name(template_names, issue)).to be('deFault')
end
it 'returns nil when issuable has a description set' do
issue = build(:issue, description: 'from template in project settings')
expect(helper.default_template_name(template_names, issue)).to be_nil
end
it 'returns nil when issuable is persisted' do
issue = create(:issue)
expect(helper.default_template_name(template_names, issue)).to be_nil
end
end
context 'when there is no default template' do
let(:template_names) { %w(another_issue_template) }
it 'returns nil' do
expect(helper.default_template_name(template_names, build(:issue))).to be_nil
end
end
end
describe '#template_names' do
let(:project) { build(:project) }
let(:templates) do
{
"Project templates" => [
{ name: "another_issue_template", id: "another_issue_template", project_id: project.id },
{ name: "custom_issue_template", id: "custom_issue_template", project_id: project.id }
],
"Group templates" => [
{ name: "another_issue_template", id: "another_issue_template", project_id: project.id }
]
}
end
before do
allow(helper).to receive(:ref_project).and_return(project)
allow(helper).to receive(:issuable_templates).and_return(templates)
end
it 'returns unique list of template names' do
expect(helper.template_names(build(:issue))).to contain_exactly('another_issue_template', 'custom_issue_template')
end
end
end

View file

@ -2,16 +2,14 @@
require 'spec_helper'
RSpec.describe Admin::BroadcastMessagesController do
RSpec.describe Admin::BroadcastMessagesController, :enable_admin_mode do
before do
sign_in(create(:admin))
end
describe 'GET /preview' do
render_views
describe 'POST /preview' do
it 'renders preview partial' do
get :preview, params: { broadcast_message: { message: "Hello, world!" } }
post preview_admin_broadcast_messages_path, params: { broadcast_message: { message: "Hello, world!" } }
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).to render_template(:_preview)

View file

@ -4,31 +4,46 @@ require 'spec_helper'
RSpec.describe Todos::Destroy::DestroyedIssuableService do
describe '#execute' do
let_it_be(:target) { create(:merge_request) }
let_it_be(:pending_todo) { create(:todo, :pending, project: target.project, target: target, user: create(:user)) }
let_it_be(:done_todo) { create(:todo, :done, project: target.project, target: target, user: create(:user)) }
let_it_be(:user) { create(:user) }
def execute
described_class.new(target.id, target.class.name).execute
end
subject { described_class.new(target.id, target.class.name).execute }
context 'when target is merge request' do
let_it_be(:target) { create(:merge_request) }
let_it_be(:pending_todo) { create(:todo, :pending, project: target.project, target: target, user: user) }
let_it_be(:done_todo) { create(:todo, :done, project: target.project, target: target, user: user) }
it 'deletes todos for specified target ID and type' do
control_count = ActiveRecord::QueryRecorder.new { execute }.count
control_count = ActiveRecord::QueryRecorder.new { subject }.count
# Create more todos for the target
create(:todo, :pending, project: target.project, target: target, user: create(:user))
create(:todo, :pending, project: target.project, target: target, user: create(:user))
create(:todo, :done, project: target.project, target: target, user: create(:user))
create(:todo, :done, project: target.project, target: target, user: create(:user))
create(:todo, :pending, project: target.project, target: target, user: user)
create(:todo, :pending, project: target.project, target: target, user: user)
create(:todo, :done, project: target.project, target: target, user: user)
create(:todo, :done, project: target.project, target: target, user: user)
expect { execute }.not_to exceed_query_limit(control_count)
expect(target.reload.todos.count).to eq(0)
expect { subject }.not_to exceed_query_limit(control_count)
end
it 'invalidates todos cache counts of todo users', :use_clean_rails_redis_caching do
expect { execute }
expect { subject }
.to change { pending_todo.user.todos_pending_count }.from(1).to(0)
.and change { done_todo.user.todos_done_count }.from(1).to(0)
end
end
context 'when target is an work item' do
let_it_be(:target) { create(:work_item) }
let_it_be(:todo1) { create(:todo, :pending, project: target.project, target: target, user: user) }
let_it_be(:todo2) { create(:todo, :done, project: target.project, target: target, user: user) }
# rubocop: disable Cop/AvoidBecomes
let_it_be(:todo3) { create(:todo, :pending, project: target.project, target: target.becomes(Issue), user: user) }
let_it_be(:todo4) { create(:todo, :done, project: target.project, target: target.becomes(Issue), user: user) }
# rubocop: enable Cop/AvoidBecomes
it 'deletes todos' do
expect { subject }.to change(Todo, :count).by(-4)
end
end
end
end