Commit f59ae04e authored by Dave Pisek's avatar Dave Pisek

Change tab-activation to use tabIndex model

Instead of activating a tab via passing down an 'active' prop to
each tab this changes leverages the `tabIndex` model to ensure
that it is the source of truth.
parent b89336eb
...@@ -16,7 +16,7 @@ import DetectedLicensesTable from './detected_licenses_table.vue'; ...@@ -16,7 +16,7 @@ import DetectedLicensesTable from './detected_licenses_table.vue';
import PipelineInfo from './pipeline_info.vue'; import PipelineInfo from './pipeline_info.vue';
import LicenseManagement from 'ee/vue_shared/license_compliance/license_management.vue'; import LicenseManagement from 'ee/vue_shared/license_compliance/license_management.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { doesHashExistInUrl } from '~/lib/utils/url_utility'; import { getLocationHash } from '~/lib/utils/url_utility';
export default { export default {
name: 'LicenseComplianceApp', name: 'LicenseComplianceApp',
...@@ -46,9 +46,10 @@ export default { ...@@ -46,9 +46,10 @@ export default {
}, },
data() { data() {
return { return {
tabIndex: 0, tabIndex: this.activeTabIndex(),
}; };
}, },
tabNames: ['licenses', 'policies'],
computed: { computed: {
...mapState(LICENSE_LIST, ['initialized', 'licenses', 'reportInfo', 'listTypes', 'pageInfo']), ...mapState(LICENSE_LIST, ['initialized', 'licenses', 'reportInfo', 'listTypes', 'pageInfo']),
...mapState(LICENSE_MANAGEMENT, ['managedLicenses']), ...mapState(LICENSE_MANAGEMENT, ['managedLicenses']),
...@@ -69,16 +70,24 @@ export default { ...@@ -69,16 +70,24 @@ export default {
return this.tabIndex === 0; return this.tabIndex === 0;
}, },
}, },
watch: {
tabIndex: {
handler(newTabIndex) {
window.location.hash = this.$options.tabNames[newTabIndex];
},
// this ensures that the hash will be set on creation if it is empty
immediate: true,
},
},
created() { created() {
this.fetchLicenses(); this.fetchLicenses();
}, },
methods: { methods: {
...mapActions(LICENSE_LIST, ['fetchLicenses']), ...mapActions(LICENSE_LIST, ['fetchLicenses']),
isActive(tabName) { activeTabIndex() {
return doesHashExistInUrl(tabName); const activeTabIndex = this.$options.tabNames.indexOf(getLocationHash());
},
setActive(tabName) { return activeTabIndex !== -1 ? activeTabIndex : 0;
window.location.hash = tabName;
}, },
}, },
}; };
...@@ -128,11 +137,7 @@ export default { ...@@ -128,11 +137,7 @@ export default {
<!-- TODO: Remove feature flag --> <!-- TODO: Remove feature flag -->
<template v-if="hasLicensePolicyList"> <template v-if="hasLicensePolicyList">
<gl-tabs v-model="tabIndex" content-class="pt-0"> <gl-tabs v-model="tabIndex" content-class="pt-0">
<gl-tab <gl-tab>
data-testid="licenses"
:active="isActive('licenses')"
@click="setActive('licenses')"
>
<template #title> <template #title>
{{ s__('Licenses|Detected in Project') }} {{ s__('Licenses|Detected in Project') }}
<gl-badge pill>{{ licenseCount }}</gl-badge> <gl-badge pill>{{ licenseCount }}</gl-badge>
...@@ -141,11 +146,7 @@ export default { ...@@ -141,11 +146,7 @@ export default {
<detected-licenses-table /> <detected-licenses-table />
</gl-tab> </gl-tab>
<gl-tab <gl-tab>
data-testid="policies"
:active="isActive('policies')"
@click="setActive('policies')"
>
<template #title> <template #title>
{{ s__('Licenses|Policies') }} {{ s__('Licenses|Policies') }}
<gl-badge pill>{{ policyCount }}</gl-badge> <gl-badge pill>{{ policyCount }}</gl-badge>
......
...@@ -189,52 +189,47 @@ describe('Project Licenses', () => { ...@@ -189,52 +189,47 @@ describe('Project Licenses', () => {
}); });
describe.each` describe.each`
givenUrlHash | tabName | expectedActiveAttributeValue givenLocationHash | expectedTabIndex
${'#policies'} | ${'policies'} | ${'true'} ${'licenses'} | ${0}
${'#policies'} | ${'licenses'} | ${undefined} ${'policies'} | ${1}
${'#licenses'} | ${'licenses'} | ${'true'} ${'foo'} | ${0}
${'#licenses'} | ${'policies'} | ${undefined} ${'bar'} | ${0}
${'#foo'} | ${'policies'} | ${undefined} `('when the url contains $givenUrlHash hash', ({ givenLocationHash, expectedTabIndex }) => {
${'#foo'} | ${'licenses'} | ${undefined} beforeEach(() => {
`( setWindowLocation({
'when the url contains $givenUrlHash hash', href: `${TEST_HOST}#${givenLocationHash}`,
({ givenUrlHash, tabName, expectedActiveAttributeValue }) => {
beforeEach(() => {
setWindowLocation({
href: `${TEST_HOST}${givenUrlHash}`,
});
createComponent({
state: {
initialized: true,
},
options: {
provide: {
glFeatures: { licensePolicyList: true },
},
},
});
}); });
it(`${tabName} tab has "active" attribute set to be ${expectedActiveAttributeValue}`, () => { createComponent({
expect(wrapper.find(`[data-testid=${tabName}]`).attributes('active')).toBe( state: {
expectedActiveAttributeValue, initialized: true,
); },
options: {
provide: {
glFeatures: { licensePolicyList: true },
},
},
}); });
}, });
);
it.each(['policies', 'licenses'])(
'sets the location hash to "%s" when the corresponding tab is activated',
tabName => {
const originalHash = window.location.hash;
expect(originalHash).toBeFalsy();
wrapper.find(`[data-testid="${tabName}"]`).vm.$emit('click'); it(`sets the tabIndex to be "${expectedTabIndex}`, () => {
expect(wrapper.find(GlTabs).attributes('value')).toBe(`${expectedTabIndex}`);
});
});
expect(window.location.hash).toContain(tabName); it.each`
givenTabIndex | expectedLocationHash
${0} | ${'licenses'}
${1} | ${'policies'}
`(
'sets the location hash to "tabName" when the corresponding tab is activated',
({ givenTabIndex, expectedLocationHash }) => {
wrapper.setData({ tabIndex: givenTabIndex });
wrapper.vm.$forceUpdate();
window.location.hash = originalHash; return wrapper.vm.$nextTick().then(() => {
expect(window.location.hash).toBe(expectedLocationHash);
});
}, },
); );
......
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