Commit 26b314b2 authored by Rajat Jain's avatar Rajat Jain

Restrict HealthStatus for Ultimate License

Right now HealthStatus is exposed for all the EE licenses. This adds
a restriction to only Ultimate licenses.
parent ccd02e1a
...@@ -16,13 +16,22 @@ export default { ...@@ -16,13 +16,22 @@ export default {
EpicActionsSplitButton, EpicActionsSplitButton,
}, },
computed: { computed: {
...mapState(['parentItem', 'descendantCounts', 'healthStatus', 'allowSubEpics']), ...mapState([
'parentItem',
'descendantCounts',
'healthStatus',
'allowSubEpics',
'allowIssuableHealthStatus',
]),
totalEpicsCount() { totalEpicsCount() {
return this.descendantCounts.openedEpics + this.descendantCounts.closedEpics; return this.descendantCounts.openedEpics + this.descendantCounts.closedEpics;
}, },
totalIssuesCount() { totalIssuesCount() {
return this.descendantCounts.openedIssues + this.descendantCounts.closedIssues; return this.descendantCounts.openedIssues + this.descendantCounts.closedIssues;
}, },
showHealthStatus() {
return this.healthStatus && this.allowIssuableHealthStatus;
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -90,10 +99,10 @@ export default { ...@@ -90,10 +99,10 @@ export default {
<span class="d-inline-flex align-items-center" :class="{ 'ml-2': allowSubEpics }"> <span class="d-inline-flex align-items-center" :class="{ 'ml-2': allowSubEpics }">
<gl-icon name="issues" class="mr-1" /> <gl-icon name="issues" class="mr-1" />
{{ totalIssuesCount }} {{ totalIssuesCount }}
<span class="ml-2 bullet-separator">&bull;</span> <span v-if="showHealthStatus" class="ml-2 bullet-separator">&bull;</span>
</span> </span>
</div> </div>
<epic-health-status v-if="healthStatus" :health-status="healthStatus" /> <epic-health-status v-if="showHealthStatus" :health-status="healthStatus" />
</div> </div>
<div <div
v-if="parentItem.userPermissions.adminEpic" v-if="parentItem.userPermissions.adminEpic"
......
...@@ -54,7 +54,7 @@ export default { ...@@ -54,7 +54,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['childrenFlags', 'userSignedIn', 'allowSubEpics']), ...mapState(['childrenFlags', 'userSignedIn', 'allowSubEpics', 'allowIssuableHealthStatus']),
itemReference() { itemReference() {
return this.item.reference; return this.item.reference;
}, },
...@@ -122,6 +122,9 @@ export default { ...@@ -122,6 +122,9 @@ export default {
isIssue() { isIssue() {
return this.item.type === ChildType.Issue; return this.item.type === ChildType.Issue;
}, },
showHealthStatus() {
return this.item.healthStatus && this.allowIssuableHealthStatus;
},
}, },
methods: { methods: {
...mapActions(['setRemoveItemModalProps']), ...mapActions(['setRemoveItemModalProps']),
...@@ -221,17 +224,17 @@ export default { ...@@ -221,17 +224,17 @@ export default {
<gl-icon name="issues" class="mr-1" /> <gl-icon name="issues" class="mr-1" />
{{ totalIssuesCount }} {{ totalIssuesCount }}
</span> </span>
<span class="ml-2 bullet-separator">&bull;</span> <span v-if="showHealthStatus" class="ml-2 bullet-separator">&bull;</span>
</div> </div>
<div v-if="item.healthStatus" class="item-health-status mr-2"> <div v-if="showHealthStatus" class="item-health-status mr-2">
<epic-health-status v-if="isEpic" :health-status="item.healthStatus" /> <epic-health-status v-if="isEpic" :health-status="item.healthStatus" />
<issue-health-status v-else-if="isIssue" :health-status="item.healthStatus" /> <issue-health-status v-else-if="isIssue" :health-status="item.healthStatus" />
</div> </div>
<div class="item-meta-child d-flex align-items-center order-0 flex-wrap flex-xl-nowrap"> <div class="item-meta-child d-flex align-items-center order-0 flex-wrap flex-xl-nowrap">
<!-- This bullet is for Milestone --> <!-- This bullet is for Milestone -->
<span v-if="item.healthStatus && hasMilestone" class="bullet-separator mr-2" <span v-if="showHealthStatus && hasMilestone" class="bullet-separator mr-2"
>&bull;</span >&bull;</span
> >
...@@ -243,7 +246,7 @@ export default { ...@@ -243,7 +246,7 @@ export default {
<!-- This bullet is for Due Date --> <!-- This bullet is for Due Date -->
<span <span
v-if="(hasMilestone || item.healthStatus) && item.dueDate" v-if="(hasMilestone || showHealthStatus) && item.dueDate"
class="mr-2 bullet-separator" class="mr-2 bullet-separator"
>&bull;</span >&bull;</span
> >
...@@ -257,7 +260,7 @@ export default { ...@@ -257,7 +260,7 @@ export default {
<!-- This bullet is for Weight --> <!-- This bullet is for Weight -->
<span <span
v-if="(item.dueDate || hasMilestone || item.healthStatus) && item.weight" v-if="(item.dueDate || hasMilestone || showHealthStatus) && item.weight"
class="mr-2 bullet-separator" class="mr-2 bullet-separator"
>&bull;</span >&bull;</span
> >
...@@ -272,9 +275,7 @@ export default { ...@@ -272,9 +275,7 @@ export default {
<!-- This bullet is for Assignees --> <!-- This bullet is for Assignees -->
<span <span
v-if=" v-if="(item.dueDate || hasMilestone || showHealthStatus || item.weight) && hasAssignees"
(item.dueDate || hasMilestone || item.healthStatus || item.weight) && hasAssignees
"
class="mr-2 bullet-separator" class="mr-2 bullet-separator"
>&bull;</span >&bull;</span
> >
......
...@@ -26,6 +26,7 @@ export default () => { ...@@ -26,6 +26,7 @@ export default () => {
autoCompleteIssues, autoCompleteIssues,
userSignedIn, userSignedIn,
allowSubEpics, allowSubEpics,
allowIssuableHealthStatus,
} = el.dataset; } = el.dataset;
const initialData = JSON.parse(el.dataset.initial); const initialData = JSON.parse(el.dataset.initial);
...@@ -57,6 +58,7 @@ export default () => { ...@@ -57,6 +58,7 @@ export default () => {
autoCompleteIssues: parseBoolean(autoCompleteIssues), autoCompleteIssues: parseBoolean(autoCompleteIssues),
userSignedIn: parseBoolean(userSignedIn), userSignedIn: parseBoolean(userSignedIn),
allowSubEpics: parseBoolean(allowSubEpics), allowSubEpics: parseBoolean(allowSubEpics),
allowIssuableHealthStatus: parseBoolean(allowIssuableHealthStatus),
}); });
}, },
methods: { methods: {
......
...@@ -14,6 +14,7 @@ export default { ...@@ -14,6 +14,7 @@ export default {
projectsEndpoint, projectsEndpoint,
userSignedIn, userSignedIn,
allowSubEpics, allowSubEpics,
allowIssuableHealthStatus,
}, },
) { ) {
state.epicsEndpoint = epicsEndpoint; state.epicsEndpoint = epicsEndpoint;
...@@ -23,6 +24,7 @@ export default { ...@@ -23,6 +24,7 @@ export default {
state.projectsEndpoint = projectsEndpoint; state.projectsEndpoint = projectsEndpoint;
state.userSignedIn = userSignedIn; state.userSignedIn = userSignedIn;
state.allowSubEpics = allowSubEpics; state.allowSubEpics = allowSubEpics;
state.allowIssuableHealthStatus = allowIssuableHealthStatus;
}, },
[types.SET_INITIAL_PARENT_ITEM](state, data) { [types.SET_INITIAL_PARENT_ITEM](state, data) {
......
...@@ -44,6 +44,8 @@ export default () => ({ ...@@ -44,6 +44,8 @@ export default () => ({
autoCompleteEpics: false, autoCompleteEpics: false,
autoCompleteIssues: false, autoCompleteIssues: false,
allowSubEpics: false, allowSubEpics: false,
allowIssuableHealthStatus: false,
removeItemModalProps: { removeItemModalProps: {
parentItem: {}, parentItem: {},
item: {}, item: {},
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
- epic_reference = @epic.to_reference - epic_reference = @epic.to_reference
- sub_epics_feature_available = @group.feature_available?(:subepics) - sub_epics_feature_available = @group.feature_available?(:subepics)
- issuable_health_status_feature_available = @group.feature_available?(:issuable_health_status)
- allow_sub_epics = sub_epics_feature_available ? 'true' : 'false' - allow_sub_epics = sub_epics_feature_available ? 'true' : 'false'
- allow_issuable_health_status = issuable_health_status_feature_available ? 'true' : 'false'
- add_to_breadcrumbs _("Epics"), group_epics_path(@group) - add_to_breadcrumbs _("Epics"), group_epics_path(@group)
- breadcrumb_title epic_reference - breadcrumb_title epic_reference
...@@ -42,6 +45,7 @@ ...@@ -42,6 +45,7 @@
auto_complete_issues: 'true', auto_complete_issues: 'true',
user_signed_in: current_user.present? ? 'true' : 'false', user_signed_in: current_user.present? ? 'true' : 'false',
allow_sub_epics: allow_sub_epics, allow_sub_epics: allow_sub_epics,
allow_issuable_health_status: allow_issuable_health_status,
initial: issuable_initial_data(@epic).to_json } } initial: issuable_initial_data(@epic).to_json } }
- if sub_epics_feature_available - if sub_epics_feature_available
#roadmap.tab-pane #roadmap.tab-pane
......
---
title: Add license restriction to HealthStatus
merge_request: 31571
author:
type: fixed
...@@ -6,7 +6,9 @@ import RelatedItemsTreeHeader from 'ee/related_items_tree/components/related_ite ...@@ -6,7 +6,9 @@ import RelatedItemsTreeHeader from 'ee/related_items_tree/components/related_ite
import createDefaultStore from 'ee/related_items_tree/store'; import createDefaultStore from 'ee/related_items_tree/store';
import * as epicUtils from 'ee/related_items_tree/utils/epic_utils'; import * as epicUtils from 'ee/related_items_tree/utils/epic_utils';
import { issuableTypesMap } from 'ee/related_issues/constants'; import { issuableTypesMap } from 'ee/related_issues/constants';
import EpicActionsSplitButton from 'ee/related_items_tree/components/epic_issue_actions_split_button.vue'; import EpicActionsSplitButton from 'ee/related_items_tree/components/epic_issue_actions_split_button.vue';
import EpicHealthStatus from 'ee/related_items_tree/components/epic_health_status.vue';
import { mockInitialConfig, mockParentItem, mockQueryResponse } from '../mock_data'; import { mockInitialConfig, mockParentItem, mockQueryResponse } from '../mock_data';
...@@ -196,6 +198,36 @@ describe('RelatedItemsTree', () => { ...@@ -196,6 +198,36 @@ describe('RelatedItemsTree', () => {
expect(findEpicsIssuesSplitButton().isVisible()).toBe(true); expect(findEpicsIssuesSplitButton().isVisible()).toBe(true);
}); });
describe('when issuable-health-status feature is not available', () => {
beforeEach(() => {
wrapper.vm.$store.commit('SET_INITIAL_CONFIG', {
...mockInitialConfig,
allowIssuableHealthStatus: false,
});
return wrapper.vm.$nextTick();
});
it('does not render health status', () => {
expect(wrapper.find(EpicHealthStatus).exists()).toBe(false);
});
});
describe('when issuable-health-status feature is available', () => {
beforeEach(() => {
wrapper.vm.$store.commit('SET_INITIAL_CONFIG', {
...mockInitialConfig,
allowIssuableHealthStatus: true,
});
return wrapper.vm.$nextTick();
});
it('does not render health status', () => {
expect(wrapper.find(EpicHealthStatus).exists()).toBe(true);
});
});
it('renders issues count and gl-icon', () => { it('renders issues count and gl-icon', () => {
const issuesEl = wrapper.findAll('.issue-count-badge > span').at(1); const issuesEl = wrapper.findAll('.issue-count-badge > span').at(1);
const issueIcon = issuesEl.find(GlIcon); const issueIcon = issuesEl.find(GlIcon);
......
...@@ -363,6 +363,25 @@ describe('RelatedItemsTree', () => { ...@@ -363,6 +363,25 @@ describe('RelatedItemsTree', () => {
epicWrapper.destroy(); epicWrapper.destroy();
}); });
it('renders health status when feature', () => {
function testExistence(exists) {
const healthStatus = wrapper.find('.item-health-status').exists();
expect(healthStatus).toBe(exists);
}
testExistence(false);
wrapper.vm.$store.commit('SET_INITIAL_CONFIG', {
...mockInitialConfig,
allowIssuableHealthStatus: true,
});
return wrapper.vm.$nextTick(() => {
testExistence(true);
});
});
}); });
}); });
}); });
...@@ -20,6 +20,7 @@ describe('RelatedItemsTree', () => { ...@@ -20,6 +20,7 @@ describe('RelatedItemsTree', () => {
autoCompleteEpics: true, autoCompleteEpics: true,
autoCompleteIssues: false, autoCompleteIssues: false,
allowSubEpics: true, allowSubEpics: true,
allowIssuableHealthStatus: true,
}; };
mutations[types.SET_INITIAL_CONFIG](state, data); mutations[types.SET_INITIAL_CONFIG](state, data);
...@@ -29,6 +30,7 @@ describe('RelatedItemsTree', () => { ...@@ -29,6 +30,7 @@ describe('RelatedItemsTree', () => {
expect(state).toHaveProperty('autoCompleteEpics', true); expect(state).toHaveProperty('autoCompleteEpics', true);
expect(state).toHaveProperty('autoCompleteIssues', false); expect(state).toHaveProperty('autoCompleteIssues', false);
expect(state).toHaveProperty('allowSubEpics', true); expect(state).toHaveProperty('allowSubEpics', true);
expect(state).toHaveProperty('allowIssuableHealthStatus', true);
expect(state).toHaveProperty('healthStatus', { expect(state).toHaveProperty('healthStatus', {
issuesNeedingAttention: 0, issuesNeedingAttention: 0,
issuesAtRisk: 0, issuesAtRisk: 0,
......
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