Commit 30741c7a authored by Miguel Rincon's avatar Miguel Rincon

Merge branch 'jira-issue-entity-add-gitlab-web-url' into 'master'

Add `gitlab_web_url` to Jira issue entity

See merge request gitlab-org/gitlab!53804
parents 14acddd8 72121e71
......@@ -4,6 +4,7 @@ import { GlLink, GlIcon, GlLabel, GlFormCheckbox, GlTooltipDirective } from '@gi
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { getTimeago } from '~/lib/utils/datetime_utility';
import { isExternal, setUrlFragment } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import IssuableAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
......@@ -47,17 +48,14 @@ export default {
author() {
return this.issuable.author;
},
webUrl() {
return this.issuable.gitlabWebUrl || this.issuable.webUrl;
},
authorId() {
return getIdFromGraphQLId(`${this.author.id}`);
},
isIssuableUrlExternal() {
// Check if URL is relative, which means it is internal.
if (!/^https?:\/\//g.test(this.issuable.webUrl)) {
return false;
}
// In case URL is absolute, it may or may not be internal,
// hence use `gon.gitlab_url` which is current instance domain.
return !this.issuable.webUrl.includes(gon.gitlab_url);
return isExternal(this.webUrl);
},
labels() {
return this.issuable.labels?.nodes || this.issuable.labels || [];
......@@ -91,6 +89,9 @@ export default {
this.hasSlotContents('status') || this.showDiscussions || this.issuable.assignees,
);
},
issuableNotesLink() {
return setUrlFragment(this.webUrl, 'notes');
},
},
methods: {
hasSlotContents(slotName) {
......@@ -144,7 +145,7 @@ export default {
name="eye-slash"
:title="__('Confidential')"
/>
<gl-link :href="issuable.webUrl" v-bind="issuableTitleProps"
<gl-link :href="webUrl" v-bind="issuableTitleProps"
>{{ issuable.title
}}<gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2"
/></gl-link>
......@@ -206,7 +207,7 @@ export default {
<gl-link
v-gl-tooltip:tooltipcontainer.top
:title="__('Comments')"
:href="`${issuable.webUrl}#notes`"
:href="issuableNotesLink"
:class="{ 'no-comments': !issuable.userDiscussionsCount }"
class="gl-reset-color!"
>
......
......@@ -3,6 +3,8 @@
module Integrations
module Jira
class IssueEntity < Grape::Entity
include RequestAwareEntity
expose :project_id do |_jira_issue, options|
options[:project].id
end
......@@ -61,6 +63,14 @@ module Integrations
"#{base_web_url(jira_issue)}/browse/#{jira_issue.key}"
end
expose :gitlab_web_url do |jira_issue|
if ::Feature.enabled?(:jira_issues_show_integration, options[:project], default_enabled: :yaml)
project_integrations_jira_issue_path(options[:project], jira_issue.key)
else
nil
end
end
expose :references do |jira_issue|
{
relative: jira_issue.key
......
......@@ -56,6 +56,7 @@ RSpec.describe Integrations::Jira::IssueEntity do
{ name: 'assignee' }
],
web_url: 'http://jira.com/browse/GL-5',
gitlab_web_url: Gitlab::Routing.url_helpers.project_integrations_jira_issue_path(project, 'GL-5'),
references: { relative: 'GL-5' },
external_tracker: 'jira'
)
......@@ -109,4 +110,14 @@ RSpec.describe Integrations::Jira::IssueEntity do
expect(subject).to include(labels: [])
end
end
context 'feature flag "jira_issues_show_integration" is disabled' do
before do
stub_feature_flags(jira_issues_show_integration: false)
end
it 'sets `gitlab_web_url` to nil' do
expect(subject[:gitlab_web_url]).to eq(nil)
end
end
end
......@@ -18,6 +18,8 @@ const createComponent = ({ issuableSymbol = '#', issuable = mockIssuable, slots
slots,
});
const MOCK_GITLAB_URL = 'http://0.0.0.0:3000';
describe('IssuableItem', () => {
// The mock data is dependent that this is after our default date
useFakeDate(2020, 11, 11);
......@@ -28,7 +30,7 @@ describe('IssuableItem', () => {
let wrapper;
beforeEach(() => {
gon.gitlab_url = 'http://0.0.0.0:3000';
gon.gitlab_url = MOCK_GITLAB_URL;
wrapper = createComponent();
});
......@@ -73,11 +75,11 @@ describe('IssuableItem', () => {
describe('isIssuableUrlExternal', () => {
it.each`
issuableWebUrl | urlType | returnValue
${'/gitlab-org/gitlab-test/-/issues/2'} | ${'relative'} | ${false}
${'http://0.0.0.0:3000/gitlab-org/gitlab-test/-/issues/1'} | ${'absolute and internal'} | ${false}
${'http://jira.atlassian.net/browse/IG-1'} | ${'external'} | ${true}
${'https://github.com/gitlabhq/gitlabhq/issues/1'} | ${'external'} | ${true}
issuableWebUrl | urlType | returnValue
${'/gitlab-org/gitlab-test/-/issues/2'} | ${'relative'} | ${false}
${`${MOCK_GITLAB_URL}/gitlab-org/gitlab-test/-/issues/1`} | ${'absolute and internal'} | ${false}
${'http://jira.atlassian.net/browse/IG-1'} | ${'external'} | ${true}
${'https://github.com/gitlabhq/gitlabhq/issues/1'} | ${'external'} | ${true}
`(
'returns $returnValue when `issuable.webUrl` is $urlType',
async ({ issuableWebUrl, returnValue }) => {
......@@ -217,14 +219,32 @@ describe('IssuableItem', () => {
});
describe('template', () => {
it('renders issuable title', () => {
const titleEl = wrapper.find('[data-testid="issuable-title"]');
it.each`
gitlabWebUrl | webUrl | expectedHref | expectedTarget
${undefined} | ${`${MOCK_GITLAB_URL}/issue`} | ${`${MOCK_GITLAB_URL}/issue`} | ${undefined}
${undefined} | ${'https://jira.com/issue'} | ${'https://jira.com/issue'} | ${'_blank'}
${'/gitlab-org/issue'} | ${'https://jira.com/issue'} | ${'/gitlab-org/issue'} | ${undefined}
`(
'renders issuable title correctly when `gitlabWebUrl` is `$gitlabWebUrl` and webUrl is `$webUrl`',
async ({ webUrl, gitlabWebUrl, expectedHref, expectedTarget }) => {
wrapper.setProps({
issuable: {
...mockIssuable,
webUrl,
gitlabWebUrl,
},
});
expect(titleEl.exists()).toBe(true);
expect(titleEl.find(GlLink).attributes('href')).toBe(mockIssuable.webUrl);
expect(titleEl.find(GlLink).attributes('target')).not.toBeDefined();
expect(titleEl.find(GlLink).text()).toBe(mockIssuable.title);
});
await wrapper.vm.$nextTick();
const titleEl = wrapper.find('[data-testid="issuable-title"]');
expect(titleEl.exists()).toBe(true);
expect(titleEl.find(GlLink).attributes('href')).toBe(expectedHref);
expect(titleEl.find(GlLink).attributes('target')).toBe(expectedTarget);
expect(titleEl.find(GlLink).text()).toBe(mockIssuable.title);
},
);
it('renders checkbox when `showCheckbox` prop is true', async () => {
wrapper.setProps({
......
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