Commit 8400d5c5 authored by Simon Knox's avatar Simon Knox

Merge branch '356013-make-linked-items-autocomplete-context-aware' into 'master'

Fix incorrect autocompletion and missing license check in related items UI

See merge request gitlab-org/gitlab!83022
parents b8f0feeb 758cb5e8
...@@ -85,6 +85,16 @@ export default { ...@@ -85,6 +85,16 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
autoCompleteEpics: {
type: Boolean,
required: false,
default: true,
},
autoCompleteIssues: {
type: Boolean,
required: false,
default: true,
},
}, },
computed: { computed: {
hasRelatedIssues() { hasRelatedIssues() {
...@@ -198,6 +208,8 @@ export default { ...@@ -198,6 +208,8 @@ export default {
:input-value="inputValue" :input-value="inputValue"
:pending-references="pendingReferences" :pending-references="pendingReferences"
:auto-complete-sources="autoCompleteSources" :auto-complete-sources="autoCompleteSources"
:auto-complete-epics="autoCompleteEpics"
:auto-complete-issues="autoCompleteIssues"
:path-id-separator="pathIdSeparator" :path-id-separator="pathIdSeparator"
@pendingIssuableRemoveRequest="$emit('pendingIssuableRemoveRequest', $event)" @pendingIssuableRemoveRequest="$emit('pendingIssuableRemoveRequest', $event)"
@addIssuableFormInput="$emit('addIssuableFormInput', $event)" @addIssuableFormInput="$emit('addIssuableFormInput', $event)"
......
...@@ -71,6 +71,16 @@ export default { ...@@ -71,6 +71,16 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
autoCompleteEpics: {
type: Boolean,
required: false,
default: true,
},
autoCompleteIssues: {
type: Boolean,
required: false,
default: true,
},
pathIdSeparator: { pathIdSeparator: {
type: String, type: String,
required: false, required: false,
...@@ -241,6 +251,8 @@ export default { ...@@ -241,6 +251,8 @@ export default {
:is-form-visible="isFormVisible" :is-form-visible="isFormVisible"
:input-value="inputValue" :input-value="inputValue"
:auto-complete-sources="autoCompleteSources" :auto-complete-sources="autoCompleteSources"
:auto-complete-epics="autoCompleteEpics"
:auto-complete-issues="autoCompleteIssues"
:issuable-type="issuableType" :issuable-type="issuableType"
:path-id-separator="pathIdSeparator" :path-id-separator="pathIdSeparator"
:show-categorized-issues="showCategorizedIssues" :show-categorized-issues="showCategorizedIssues"
......
...@@ -21,6 +21,7 @@ export default function initRelatedIssues() { ...@@ -21,6 +21,7 @@ export default function initRelatedIssues() {
showCategorizedIssues: parseBoolean( showCategorizedIssues: parseBoolean(
relatedIssuesRootElement.dataset.showCategorizedIssues, relatedIssuesRootElement.dataset.showCategorizedIssues,
), ),
autoCompleteEpics: false,
}, },
}), }),
}); });
......
...@@ -30,6 +30,7 @@ export default function initRelatedEpics() { ...@@ -30,6 +30,7 @@ export default function initRelatedEpics() {
showCategorizedIssues: parseBoolean(showCategorizedEpics), showCategorizedIssues: parseBoolean(showCategorizedEpics),
pathIdSeparator: PathIdSeparator.Epic, pathIdSeparator: PathIdSeparator.Epic,
issuableType: issuableTypesMap.EPIC, issuableType: issuableTypesMap.EPIC,
autoCompleteIssues: false,
}, },
}), }),
}); });
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
- epic_reference = @epic.to_reference - epic_reference = @epic.to_reference
- sub_epics_feature_available = @group.licensed_feature_available?(:subepics) - sub_epics_feature_available = @group.licensed_feature_available?(:subepics)
- related_epics_feature_available = @group.licensed_feature_available?(:related_epics)
- issuable_health_status_feature_available = @group.licensed_feature_available?(:issuable_health_status) - issuable_health_status_feature_available = @group.licensed_feature_available?(:issuable_health_status)
- scoped_labels_feature_available = @group.licensed_feature_available?(:scoped_labels) - scoped_labels_feature_available = @group.licensed_feature_available?(:scoped_labels)
...@@ -72,7 +73,7 @@ ...@@ -72,7 +73,7 @@
inner_height: '600', inner_height: '600',
child_epics: 'true' } } child_epics: 'true' } }
- if Feature.enabled?(:related_epics_widget, @group, default_enabled: :yaml) - if related_epics_feature_available && Feature.enabled?(:related_epics_widget, @group, default_enabled: :yaml)
#js-related-epics{ data: { endpoint: group_epic_related_epic_links_path(@group, @epic), #js-related-epics{ data: { endpoint: group_epic_related_epic_links_path(@group, @epic),
can_add_related_epics: "#{can?(current_user, :admin_related_epic_link, @epic)}", can_add_related_epics: "#{can?(current_user, :admin_related_epic_link, @epic)}",
help_path: help_page_path('user/group/epics/linked_epics'), help_path: help_page_path('user/group/epics/linked_epics'),
......
...@@ -5,13 +5,15 @@ require 'spec_helper' ...@@ -5,13 +5,15 @@ require 'spec_helper'
RSpec.describe 'Related Epics', :js do RSpec.describe 'Related Epics', :js do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) } let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, group: group) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:epic1) { create(:epic, group: group) } let_it_be(:epic1) { create(:epic, group: group) }
let_it_be(:epic2) { create(:epic, group: group) } let_it_be(:epic2) { create(:epic, group: group) }
let_it_be(:epic3) { create(:epic, group: group) } let_it_be(:epic3) { create(:epic, group: group) }
def visit_epic def visit_epic(related_epics: true)
group.add_developer(user) group.add_developer(user)
stub_licensed_features(epics: true, related_epics: true) stub_licensed_features(epics: true, related_epics: related_epics)
sign_in(user) sign_in(user)
visit group_epic_path(group, epic1) visit group_epic_path(group, epic1)
...@@ -92,13 +94,24 @@ RSpec.describe 'Related Epics', :js do ...@@ -92,13 +94,24 @@ RSpec.describe 'Related Epics', :js do
page.find('#add-related-issues-form-input').native.send_keys('&') page.find('#add-related-issues-form-input').native.send_keys('&')
end end
expect(page).to have_selector('#at-view-epics') wait_for_requests
expect(page.find('#at-view-epics')).to have_selector('li', count: 3)
expect(page).to have_selector('#at-view-epics .atwho-view-ul li', count: 3)
[epic3, epic2, epic1].each_with_index do |epic, index| [epic3, epic2, epic1].each_with_index do |epic, index|
expect(page.find("#at-view-epics li:nth-child(#{index + 1})")).to have_content("&#{epic.iid} #{epic.title}") expect(page.find("#at-view-epics li:nth-child(#{index + 1})")).to have_content("&#{epic.iid} #{epic.title}")
end end
end end
it 'epic input field does not autocomplete issues when `#` is input', :aggregate_failures do
page.within('.js-add-related-issues-form-area') do
page.find('#add-related-issues-form-input').native.send_keys('#')
end
wait_for_requests
expect(page).not_to have_selector('#at-view-issues .atwho-view-ul li', count: 1)
end
it 'user can view list of added epics as tokens within input field', :aggregate_failures do it 'user can view list of added epics as tokens within input field', :aggregate_failures do
page.within('.js-add-related-issues-form-area .add-issuable-form-input-wrapper') do page.within('.js-add-related-issues-form-area .add-issuable-form-input-wrapper') do
page.find('#add-related-issues-form-input').native.send_keys("&#{epic1.iid} ") page.find('#add-related-issues-form-input').native.send_keys("&#{epic1.iid} ")
...@@ -144,4 +157,18 @@ RSpec.describe 'Related Epics', :js do ...@@ -144,4 +157,18 @@ RSpec.describe 'Related Epics', :js do
expect(page).not_to have_selector('div[data-link-type="relates_to"]') expect(page).not_to have_selector('div[data-link-type="relates_to"]')
end end
end end
describe 'when related epics is not supported by license' do
before do
stub_feature_flags(related_epics_widget: true)
visit_epic(related_epics: false)
end
it 'user can not view related epics section under epic description', :aggregate_failures do
page.within('.js-epic-container') do
expect(page).not_to have_selector('#related-issues')
end
end
end
end end
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
issuable3, issuable3,
} from 'jest/issuable/components/related_issuable_mock_data'; } from 'jest/issuable/components/related_issuable_mock_data';
import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue'; import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue';
import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue';
import { import {
issuableTypesMap, issuableTypesMap,
linkedIssueTypesMap, linkedIssueTypesMap,
...@@ -139,6 +140,7 @@ describe('RelatedIssuesBlock', () => { ...@@ -139,6 +140,7 @@ describe('RelatedIssuesBlock', () => {
pathIdSeparator: PathIdSeparator.Issue, pathIdSeparator: PathIdSeparator.Issue,
isFormVisible: true, isFormVisible: true,
issuableType: 'issue', issuableType: 'issue',
autoCompleteEpics: false,
}, },
}); });
}); });
...@@ -146,6 +148,10 @@ describe('RelatedIssuesBlock', () => { ...@@ -146,6 +148,10 @@ describe('RelatedIssuesBlock', () => {
it('shows add related issues form', () => { it('shows add related issues form', () => {
expect(wrapper.find('.js-add-related-issues-form-area').exists()).toBe(true); expect(wrapper.find('.js-add-related-issues-form-area').exists()).toBe(true);
}); });
it('sets `autoCompleteEpics` to false for add-issuable-form', () => {
expect(wrapper.find(AddIssuableForm).props('autoCompleteEpics')).toBe(false);
});
}); });
describe('showCategorizedIssues prop', () => { describe('showCategorizedIssues prop', () => {
......
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