Commit 6b310d57 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '225818-add-an-upgrade-banner-for-non-premium-plans' into 'master'

Add an upgrade banner for non-premium plans

See merge request gitlab-org/gitlab!36725
parents 42649c60 e97dff4f
......@@ -106,10 +106,11 @@ export default {
return {
id: this.fieldId,
name: this.fieldName,
state: this.valid,
};
},
valid() {
return !this.required || !isEmpty(this.model) || !this.validated;
return !this.required || !isEmpty(this.model) || this.isNonEmptyPassword || !this.validated;
},
},
created() {
......
<script>
import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import eventHub from '../event_hub';
import {
GlFormGroup,
GlFormCheckbox,
GlFormInput,
GlSprintf,
GlLink,
GlButton,
GlCard,
} from '@gitlab/ui';
export default {
name: 'JiraIssuesFields',
......@@ -9,17 +18,30 @@ export default {
GlFormInput,
GlSprintf,
GlLink,
GlButton,
GlCard,
},
props: {
showJiraIssuesIntegration: {
type: Boolean,
required: false,
default: false,
},
initialEnableJiraIssues: {
type: Boolean,
required: false,
default: null,
},
initialProjectKey: {
type: String,
required: false,
default: null,
},
upgradePlanPath: {
type: String,
required: false,
default: null,
},
editProjectPath: {
type: String,
required: false,
......@@ -30,8 +52,25 @@ export default {
return {
enableJiraIssues: this.initialEnableJiraIssues,
projectKey: this.initialProjectKey,
validated: false,
};
},
computed: {
validProjectKey() {
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated;
},
},
created() {
eventHub.$on('validateForm', this.validateForm);
},
beforeDestroy() {
eventHub.$off('validateForm', this.validateForm);
},
methods: {
validateForm() {
this.validated = true;
},
},
};
</script>
......@@ -45,10 +84,11 @@ export default {
<p>
{{
s__(
'JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of issues and view any issue as read-only.',
'JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of Jira issues and view any issue as read-only.',
)
}}
</p>
<template v-if="showJiraIssuesIntegration">
<input name="service[issues_enabled]" type="hidden" value="false" />
<gl-form-checkbox v-model="enableJiraIssues" name="service[issues_enabled]">
{{ s__('JiraService|Enable Jira issues') }}
......@@ -60,14 +100,34 @@ export default {
}}
</template>
</gl-form-checkbox>
</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>
</div>
</gl-form-group>
<gl-form-group :label="s__('JiraService|Jira project key')">
<template v-if="showJiraIssuesIntegration">
<gl-form-group
:label="s__('JiraService|Jira project key')"
:invalid-feedback="__('This field is required.')"
:state="validProjectKey"
>
<gl-form-input
v-model="projectKey"
type="text"
name="service[project_key]"
:placeholder="s__('JiraService|e.g. AB')"
:required="enableJiraIssues"
:state="validProjectKey"
:disabled="!enableJiraIssues"
/>
</gl-form-group>
......@@ -84,5 +144,6 @@ export default {
</template>
</gl-sprintf>
</p>
</template>
</div>
</template>
......@@ -19,6 +19,7 @@ export default el => {
type,
commentDetail,
projectKey,
upgradePlanPath,
editProjectPath,
triggerEvents,
fields,
......@@ -30,6 +31,7 @@ export default el => {
commitEvents,
mergeRequestEvents,
enableComments,
showJiraIssuesIntegration,
enableJiraIssues,
} = parseBooleanInData(booleanAttributes);
......@@ -50,8 +52,10 @@ export default el => {
initialCommentDetail: commentDetail,
},
jiraIssuesProps: {
showJiraIssuesIntegration,
initialEnableJiraIssues: enableJiraIssues,
initialProjectKey: projectKey,
upgradePlanPath,
editProjectPath,
},
triggerEvents: JSON.parse(triggerEvents),
......
......@@ -15,8 +15,10 @@ module EE
if integration.is_a?(JiraService)
form_data.merge!(
show_jira_issues_integration: @project&.feature_available?(:jira_issues_integration).to_s,
enable_jira_issues: integration.issues_enabled.to_s,
project_key: integration.project_key,
upgrade_plan_path: @project && ::Gitlab::CurrentSettings.should_check_namespace_plan? ? upgrade_plan_path(@project.group) : nil,
edit_project_path: @project ? edit_project_path(@project, anchor: 'js-shared-permissions') : nil
)
end
......
......@@ -24,7 +24,7 @@ RSpec.describe EE::ServicesHelper do
let(:integration) { build(:slack_service) }
it 'does not include Jira specific fields' do
is_expected.not_to include(:enable_jira_issues, :project_key, :edit_project_path)
is_expected.not_to include(:show_jira_issues_integration, :enable_jira_issues, :project_key, :edit_project_path)
end
end
......@@ -32,7 +32,7 @@ RSpec.describe EE::ServicesHelper do
let(:integration) { build(:jira_service) }
it 'includes Jira specific fields' do
is_expected.to include(:enable_jira_issues, :project_key, :edit_project_path)
is_expected.to include(:show_jira_issues_integration, :enable_jira_issues, :project_key, :edit_project_path)
end
end
end
......
......@@ -13122,7 +13122,7 @@ msgstr ""
msgid "JiraService|Web URL"
msgstr ""
msgid "JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of issues and view any issue as read-only."
msgid "JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of Jira issues and view any issue as read-only."
msgstr ""
msgid "JiraService|e.g. AB"
......@@ -23857,6 +23857,9 @@ msgstr ""
msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed."
msgstr ""
msgid "This is a Premium feature"
msgstr ""
msgid "This is a Work in Progress"
msgstr ""
......@@ -25265,6 +25268,9 @@ msgstr ""
msgid "Upgrade plan to unlock Canary Deployments feature"
msgstr ""
msgid "Upgrade your plan"
msgstr ""
msgid "Upgrade your plan to activate Advanced Global Search."
msgstr ""
......@@ -25274,6 +25280,9 @@ 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 Issue boards."
msgstr ""
......
......@@ -189,5 +189,39 @@ describe('DynamicField', () => {
});
});
});
describe('validations', () => {
describe('password field', () => {
beforeEach(() => {
createComponent({
type: 'password',
required: true,
value: null,
});
wrapper.vm.validated = true;
});
describe('without value', () => {
it('requires validation', () => {
expect(wrapper.vm.valid).toBe(false);
expect(findGlFormGroup().classes('is-invalid')).toBe(true);
expect(findGlFormInput().classes('is-invalid')).toBe(true);
});
});
describe('with value', () => {
beforeEach(() => {
wrapper.setProps({ value: 'true' });
});
it('does not require validation', () => {
expect(wrapper.vm.valid).toBe(true);
expect(findGlFormGroup().classes('is-valid')).toBe(true);
expect(findGlFormInput().classes('is-valid')).toBe(true);
});
});
});
});
});
});
......@@ -6,6 +6,7 @@ describe('JiraIssuesFields', () => {
let wrapper;
const defaultProps = {
showJiraIssuesIntegration: true,
editProjectPath: '/edit',
};
......@@ -24,13 +25,33 @@ describe('JiraIssuesFields', () => {
const findEnableCheckbox = () => wrapper.find(GlFormCheckbox);
const findProjectKey = () => wrapper.find(GlFormInput);
const expectedBannerText = 'This is a Premium feature';
describe('template', () => {
describe('upgrade banner for non-Premium user', () => {
beforeEach(() => {
createComponent({ 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);
});
});
describe('Enable Jira issues checkbox', () => {
beforeEach(() => {
createComponent({ initialProjectKey: '' });
});
it('does not show upgrade banner', () => {
expect(wrapper.text()).not.toContain(expectedBannerText);
});
// As per https://vuejs.org/v2/guide/forms.html#Checkbox-1,
// browsers don't include unchecked boxes in form submissions.
it('includes issues_enabled as false even if unchecked', () => {
......@@ -41,6 +62,10 @@ describe('JiraIssuesFields', () => {
expect(findProjectKey().attributes('disabled')).toBe('disabled');
});
it('does not require project_key', () => {
expect(findProjectKey().attributes('required')).toBeUndefined();
});
describe('on enable issues', () => {
it('enables project_key input', () => {
findEnableCheckbox().vm.$emit('input', true);
......@@ -49,6 +74,14 @@ describe('JiraIssuesFields', () => {
expect(findProjectKey().attributes('disabled')).toBeUndefined();
});
});
it('requires project_key input', () => {
findEnableCheckbox().vm.$emit('input', true);
return wrapper.vm.$nextTick().then(() => {
expect(findProjectKey().attributes('required')).toBe('required');
});
});
});
});
......
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