Commit be3a67c0 authored by Savas Vedova's avatar Savas Vedova

Display call to action for jira issues

- Display a different messaged based on the user subscription.
- Add changelog
parent ff725188
<script>
import {
GlFormGroup,
GlFormCheckbox,
GlFormInput,
GlSprintf,
GlLink,
GlButton,
GlCard,
} from '@gitlab/ui';
import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
import JiraUpgradeCta from './jira_upgrade_cta.vue';
export default {
name: 'JiraIssuesFields',
......@@ -19,8 +12,7 @@ export default {
GlFormInput,
GlSprintf,
GlLink,
GlButton,
GlCard,
JiraUpgradeCta,
JiraIssueCreationVulnerabilities: () =>
import('ee_component/integrations/edit/components/jira_issue_creation_vulnerabilities.vue'),
},
......@@ -84,11 +76,13 @@ export default {
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated;
},
showJiraVulnerabilitiesOptions() {
return (
this.enableJiraIssues &&
this.showJiraVulnerabilitiesIntegration &&
this.glFeatures.jiraForVulnerabilities
);
return this.showJiraVulnerabilitiesIntegration && this.glFeatures.jiraForVulnerabilities;
},
showUltimateUpgrade() {
return this.showJiraIssuesIntegration && !this.showJiraVulnerabilitiesIntegration;
},
showPremiumUpgrade() {
return !this.showJiraIssuesIntegration;
},
},
created() {
......@@ -135,27 +129,23 @@ export default {
</template>
</gl-form-checkbox>
<jira-issue-creation-vulnerabilities
v-if="showJiraVulnerabilitiesOptions"
v-if="enableJiraIssues"
:project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-issue-type-id="initialVulnerabilitiesIssuetype"
:show-full-feature="showJiraVulnerabilitiesOptions"
data-testid="jira-for-vulnerabilities"
@request-get-issue-types="getJiraIssueTypes"
/>
</template>
<gl-card v-else class="gl-mt-7">
<strong>{{ __('This is a Premium feature') }}</strong>
<p>{{ __('Upgrade your plan to enable this feature of the Jira Integration.') }}</p>
<gl-button
v-if="upgradePlanPath"
category="primary"
variant="info"
:href="upgradePlanPath"
target="_blank"
>
{{ __('Upgrade your plan') }}
</gl-button>
</gl-card>
<jira-upgrade-cta
v-if="showUltimateUpgrade || showPremiumUpgrade"
class="gl-mt-2"
:class="{ 'gl-ml-6': showUltimateUpgrade }"
:upgrade-plan-path="upgradePlanPath"
:show-ultimate-message="showUltimateUpgrade"
:show-premium-message="showPremiumUpgrade"
/>
</div>
</gl-form-group>
<template v-if="showJiraIssuesIntegration">
......
<script>
import { GlButton, GlCard } from '@gitlab/ui';
import { s__, __ } from '~/locale';
export default {
components: {
GlButton,
GlCard,
},
props: {
upgradePlanPath: {
type: String,
required: false,
default: '',
},
showPremiumMessage: {
type: Boolean,
required: false,
default: false,
},
showUltimateMessage: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
title() {
return this.showUltimateMessage
? this.$options.i18n.titleUltimate
: this.$options.i18n.titlePremium;
},
},
i18n: {
titleUltimate: s__('JiraService|This is an Ultimate feature'),
titlePremium: s__('JiraService|This is a Premium feature'),
content: s__('JiraService|Upgrade your plan to enable this feature of the Jira Integration.'),
upgrade: __('Upgrade your plan'),
},
};
</script>
<template>
<gl-card>
<strong>{{ title }}</strong>
<p>{{ $options.i18n.content }}</p>
<gl-button v-if="upgradePlanPath" category="primary" variant="info" :href="upgradePlanPath">
{{ $options.i18n.upgrade }}
</gl-button>
</gl-card>
</template>
......@@ -50,6 +50,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
showFullFeature: {
type: Boolean,
required: false,
default: true,
},
projectKey: {
type: String,
required: false,
......@@ -129,71 +134,74 @@ export default {
<gl-form-checkbox
v-model="isJiraVulnerabilitiesEnabled"
data-testid="enable-jira-vulnerabilities"
:disabled="!showFullFeature"
>
{{ $options.i18n.checkbox.label }}
<template #help>
{{ $options.i18n.checkbox.description }}
</template>
</gl-form-checkbox>
<input
name="service[vulnerabilities_enabled]"
type="hidden"
:value="isJiraVulnerabilitiesEnabled"
/>
<gl-form-group
v-if="isJiraVulnerabilitiesEnabled"
:label="$options.i18n.issueTypeSelect.label"
class="gl-mt-4 gl-pl-1 gl-ml-5"
data-testid="issue-type-section"
>
<p>{{ $options.i18n.issueTypeSelect.description }}</p>
<gl-alert
v-if="shouldShowLoadingErrorAlert"
class="gl-mb-5"
variant="danger"
:title="$options.i18n.fetchIssueTypesErrorMessage"
@dismiss="isLoadingErrorAlertDimissed = true"
<template v-if="showFullFeature">
<input
name="service[vulnerabilities_enabled]"
type="hidden"
:value="isJiraVulnerabilitiesEnabled"
/>
<gl-form-group
v-if="isJiraVulnerabilitiesEnabled"
:label="$options.i18n.issueTypeSelect.label"
class="gl-mt-4 gl-pl-1 gl-ml-5"
data-testid="issue-type-section"
>
{{ loadingJiraIssueTypesErrorMessage }}
</gl-alert>
<div class="row gl-display-flex gl-align-items-center">
<gl-button-group class="col-md-5 gl-mr-3">
<input
name="service[vulnerabilities_issuetype]"
type="hidden"
:value="checkedIssueType.id || initialIssueTypeId"
/>
<gl-dropdown
class="gl-w-full"
:disabled="!jiraIssueTypes.length"
:loading="isLoadingJiraIssueTypes || isTesting"
:text="checkedIssueType.name || $options.i18n.issueTypeSelect.defaultText"
>
<gl-dropdown-item
v-for="jiraIssueType in jiraIssueTypes"
:key="jiraIssueType.id"
:is-checked="checkedIssueType.id === jiraIssueType.id"
is-check-item
@click="selectedJiraIssueType = jiraIssueType"
<p>{{ $options.i18n.issueTypeSelect.description }}</p>
<gl-alert
v-if="shouldShowLoadingErrorAlert"
class="gl-mb-5"
variant="danger"
:title="$options.i18n.fetchIssueTypesErrorMessage"
@dismiss="isLoadingErrorAlertDimissed = true"
>
{{ loadingJiraIssueTypesErrorMessage }}
</gl-alert>
<div class="row gl-display-flex gl-align-items-center">
<gl-button-group class="col-md-5 gl-mr-3">
<input
name="service[vulnerabilities_issuetype]"
type="hidden"
:value="checkedIssueType.id || initialIssueTypeId"
/>
<gl-dropdown
class="gl-w-full"
:disabled="!jiraIssueTypes.length"
:loading="isLoadingJiraIssueTypes || isTesting"
:text="checkedIssueType.name || $options.i18n.issueTypeSelect.defaultText"
>
{{ jiraIssueType.name }}
</gl-dropdown-item>
</gl-dropdown>
<gl-button
v-gl-tooltip.hover
:title="$options.i18n.fetchIssueTypesButtonLabel"
:aria-label="$options.i18n.fetchIssueTypesButtonLabel"
:disabled="!projectKey"
icon="retry"
data-testid="fetch-issue-types"
@click="handleLoadJiraIssueTypesClick"
/>
</gl-button-group>
<p v-if="projectKeyWarning" class="gl-my-0">
<gl-icon name="warning" class="gl-text-orange-500" />
{{ projectKeyWarning }}
</p>
</div>
</gl-form-group>
<gl-dropdown-item
v-for="jiraIssueType in jiraIssueTypes"
:key="jiraIssueType.id"
:is-checked="checkedIssueType.id === jiraIssueType.id"
is-check-item
@click="selectedJiraIssueType = jiraIssueType"
>
{{ jiraIssueType.name }}
</gl-dropdown-item>
</gl-dropdown>
<gl-button
v-gl-tooltip.hover
:title="$options.i18n.fetchIssueTypesButtonLabel"
:aria-label="$options.i18n.fetchIssueTypesButtonLabel"
:disabled="!projectKey"
icon="retry"
data-testid="fetch-issue-types"
@click="handleLoadJiraIssueTypesClick"
/>
</gl-button-group>
<p v-if="projectKeyWarning" class="gl-my-0">
<gl-icon name="warning" class="gl-text-orange-500" />
{{ projectKeyWarning }}
</p>
</div>
</gl-form-group>
</template>
</div>
</template>
---
title: Display ultimate or premium upgrade plan banner for jira issues
merge_request: 58877
author:
type: added
......@@ -51,7 +51,6 @@ describe('JiraIssuesFields', () => {
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('content', () => {
......@@ -101,6 +100,16 @@ describe('JiraIssuesFields', () => {
});
});
describe('when showFullFeature is off', () => {
beforeEach(() => {
wrapper = createShallowComponent({ props: { showFullFeature: false } });
});
it('does not show the issue type section', () => {
expect(findIssueTypeSection().exists()).toBe(false);
});
});
describe('Jira issue type dropdown', () => {
describe('with no Jira issues fetched', () => {
beforeEach(async () => {
......
......@@ -18031,6 +18031,12 @@ msgstr ""
msgid "JiraService|This feature requires a Premium plan."
msgstr ""
msgid "JiraService|This is a Premium feature"
msgstr ""
msgid "JiraService|This is an Ultimate feature"
msgstr ""
msgid "JiraService|This issue is synchronized with Jira"
msgstr ""
......@@ -18040,6 +18046,9 @@ msgstr ""
msgid "JiraService|Transition Jira issues to their final state:"
msgstr ""
msgid "JiraService|Upgrade your plan to enable this feature of the Jira Integration."
msgstr ""
msgid "JiraService|Use a password for server version and an API token for cloud version."
msgstr ""
......@@ -31944,9 +31953,6 @@ msgstr ""
msgid "This is a Jira user."
msgstr ""
msgid "This is a Premium feature"
msgstr ""
msgid "This is a confidential %{noteableTypeText}."
msgstr ""
......@@ -33651,9 +33657,6 @@ msgstr ""
msgid "Upgrade your plan to activate Group Webhooks."
msgstr ""
msgid "Upgrade your plan to enable this feature of the Jira Integration."
msgstr ""
msgid "Upgrade your plan to improve merge requests."
msgstr ""
......
import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import JiraUpgradeCta from '~/integrations/edit/components/jira_upgrade_cta.vue';
import eventHub from '~/integrations/edit/event_hub';
describe('JiraIssuesFields', () => {
......@@ -28,23 +28,46 @@ describe('JiraIssuesFields', () => {
}
});
const findEnableCheckbox = () => wrapper.find(GlFormCheckbox);
const findProjectKey = () => wrapper.find(GlFormInput);
const expectedBannerText = 'This is a Premium feature';
const findEnableCheckbox = () => wrapper.findComponent(GlFormCheckbox);
const findProjectKey = () => wrapper.findComponent(GlFormInput);
const findJiraUpgradeCta = () => wrapper.findComponent(JiraUpgradeCta);
const findJiraForVulnerabilities = () => wrapper.find('[data-testid="jira-for-vulnerabilities"]');
const setEnableCheckbox = async (isEnabled = true) =>
findEnableCheckbox().vm.$emit('input', isEnabled);
describe('jira issues call to action', () => {
it('shows the premium message', () => {
createComponent({
props: { showJiraIssuesIntegration: false },
});
expect(findJiraUpgradeCta().props()).toMatchObject({
showPremiumMessage: true,
showUltimateMessage: false,
});
});
it('shows the ultimate message', () => {
createComponent({
props: {
showJiraIssuesIntegration: true,
showJiraVulnerabilitiesIntegration: false,
},
});
expect(findJiraUpgradeCta().props()).toMatchObject({
showPremiumMessage: false,
showUltimateMessage: true,
});
});
});
describe('template', () => {
describe('upgrade banner for non-Premium user', () => {
beforeEach(() => {
createComponent({ props: { initialProjectKey: '', showJiraIssuesIntegration: false } });
});
it('shows upgrade banner', () => {
expect(wrapper.text()).toContain(expectedBannerText);
});
it('does not show checkbox and input field', () => {
expect(findEnableCheckbox().exists()).toBe(false);
expect(findProjectKey().exists()).toBe(false);
......@@ -57,7 +80,7 @@ describe('JiraIssuesFields', () => {
});
it('does not show upgrade banner', () => {
expect(wrapper.text()).not.toContain(expectedBannerText);
expect(findJiraUpgradeCta().exists()).toBe(false);
});
// As per https://vuejs.org/v2/guide/forms.html#Checkbox-1,
......@@ -125,6 +148,14 @@ describe('JiraIssuesFields', () => {
},
);
it('passes down the correct show-full-feature property', async () => {
await setEnableCheckbox(true);
expect(findJiraForVulnerabilities().attributes('show-full-feature')).toBe('true');
wrapper.setProps({ showJiraVulnerabilitiesIntegration: false });
await wrapper.vm.$nextTick();
expect(findJiraForVulnerabilities().attributes('show-full-feature')).toBeUndefined();
});
it('passes down the correct initial-issue-type-id value when value is empty', async () => {
await setEnableCheckbox(true);
expect(findJiraForVulnerabilities().attributes('initial-issue-type-id')).toBeUndefined();
......
import { shallowMount } from '@vue/test-utils';
import JiraUpgradeCta from '~/integrations/edit/components/jira_upgrade_cta.vue';
describe('JiraUpgradeCta', () => {
let wrapper;
const contentMessage = 'Upgrade your plan to enable this feature of the Jira Integration.';
const createComponent = (propsData) => {
wrapper = shallowMount(JiraUpgradeCta, {
propsData,
});
};
afterEach(() => {
wrapper.destroy();
});
it('displays the correct message for premium and lower users', () => {
createComponent({ showPremiumMessage: true });
expect(wrapper.html()).toContain('This is a Premium feature');
expect(wrapper.html()).toContain(contentMessage);
});
it('displays the correct message for ultimate and lower users', () => {
createComponent({ showUltimateMessage: true });
expect(wrapper.html()).toContain('This is an Ultimate feature');
expect(wrapper.html()).toContain(contentMessage);
});
});
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