Commit 99348ebe authored by Dave Pisek's avatar Dave Pisek

Add locationHash support to DAST scanner-profile library

This commit adds support for linking to a scanner-profile within
the DAST on-demand scanner-profile library by setting a location hash.
parent 671f008c
<script> <script>
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { GlDropdown, GlDropdownItem, GlTab, GlTabs } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlTab, GlTabs } from '@gitlab/ui';
import { camelCase, kebabCase } from 'lodash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { getLocationHash } from '~/lib/utils/url_utility';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ProfilesList from './dast_profiles_list.vue'; import ProfilesList from './dast_profiles_list.vue';
import * as cacheUtils from '../graphql/cache_utils'; import * as cacheUtils from '../graphql/cache_utils';
...@@ -46,11 +48,23 @@ export default { ...@@ -46,11 +48,23 @@ export default {
glFeatures, glFeatures,
); );
}, },
tabIndex: {
get() {
const activeTabIndex = Object.keys(this.profileSettings).indexOf(
camelCase(getLocationHash()),
);
return Math.max(0, activeTabIndex);
},
},
}, },
created() { created() {
this.addSmartQueriesForEnabledProfileTypes(); this.addSmartQueriesForEnabledProfileTypes();
}, },
methods: { methods: {
setLocationHash(profileType) {
window.location.hash = kebabCase(profileType);
},
addSmartQueriesForEnabledProfileTypes() { addSmartQueriesForEnabledProfileTypes() {
Object.values(this.profileSettings).forEach(({ profileType, graphQL: { query } }) => { Object.values(this.profileSettings).forEach(({ profileType, graphQL: { query } }) => {
this.makeProfileTypeReactive(profileType); this.makeProfileTypeReactive(profileType);
...@@ -227,10 +241,14 @@ export default { ...@@ -227,10 +241,14 @@ export default {
</p> </p>
</header> </header>
<gl-tabs> <gl-tabs v-model="tabIndex">
<gl-tab v-for="(data, profileType) in profileSettings" :key="profileType"> <gl-tab
v-for="(settings, profileType) in profileSettings"
:key="profileType"
@click="setLocationHash(profileType)"
>
<template #title> <template #title>
<span>{{ profileSettings[profileType].i18n.tabName }}</span> <span>{{ settings.i18n.tabName }}</span>
</template> </template>
<profiles-list <profiles-list
...@@ -241,7 +259,7 @@ export default { ...@@ -241,7 +259,7 @@ export default {
:is-loading="isLoadingProfiles(profileType)" :is-loading="isLoadingProfiles(profileType)"
:profiles-per-page="$options.profilesPerPage" :profiles-per-page="$options.profilesPerPage"
:profiles="profileTypes[profileType].profiles" :profiles="profileTypes[profileType].profiles"
:fields="profileSettings[profileType].tableFields" :fields="settings.tableFields"
@load-more-profiles="fetchMoreProfiles(profileType)" @load-more-profiles="fetchMoreProfiles(profileType)"
@delete-profile="deleteProfile(profileType, $event)" @delete-profile="deleteProfile(profileType, $event)"
/> />
......
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount, createWrapper } from '@vue/test-utils';
import { within } from '@testing-library/dom'; import { within } from '@testing-library/dom';
import { merge } from 'lodash'; import { merge } from 'lodash';
import { GlDropdown } from '@gitlab/ui'; import { GlDropdown } from '@gitlab/ui';
import setWindowLocation from 'helpers/set_window_location_helper';
import DastProfiles from 'ee/dast_profiles/components/dast_profiles.vue'; import DastProfiles from 'ee/dast_profiles/components/dast_profiles.vue';
const TEST_NEW_DAST_SCANNER_PROFILE_PATH = '/-/on_demand_scans/scanner_profiles/new'; const TEST_NEW_DAST_SCANNER_PROFILE_PATH = '/-/on_demand_scans/scanner_profiles/new';
...@@ -81,6 +82,11 @@ describe('EE - DastProfiles', () => { ...@@ -81,6 +82,11 @@ describe('EE - DastProfiles', () => {
const getDropdownComponent = () => wrapper.find(GlDropdown); const getDropdownComponent = () => wrapper.find(GlDropdown);
const getSiteProfilesDropdownItem = text => const getSiteProfilesDropdownItem = text =>
within(getDropdownComponent().element).queryByText(text); within(getDropdownComponent().element).queryByText(text);
const getTab = ({ tabName, selected }) =>
withinComponent().getByRole('tab', {
name: tabName,
selected,
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -124,6 +130,9 @@ describe('EE - DastProfiles', () => { ...@@ -124,6 +130,9 @@ describe('EE - DastProfiles', () => {
}); });
describe('tabs', () => { describe('tabs', () => {
const originalLocation = window.location;
describe('without location hash set', () => {
beforeEach(() => { beforeEach(() => {
createFullComponent(); createFullComponent();
}); });
...@@ -141,8 +150,8 @@ describe('EE - DastProfiles', () => { ...@@ -141,8 +150,8 @@ describe('EE - DastProfiles', () => {
`( `(
'shows a "$tabName" tab which has "selected" set to "$shouldBeSelectedByDefault"', 'shows a "$tabName" tab which has "selected" set to "$shouldBeSelectedByDefault"',
({ tabName, shouldBeSelectedByDefault }) => { ({ tabName, shouldBeSelectedByDefault }) => {
const tab = withinComponent().getByRole('tab', { const tab = getTab({
name: tabName, tabName,
selected: shouldBeSelectedByDefault, selected: shouldBeSelectedByDefault,
}); });
...@@ -151,6 +160,41 @@ describe('EE - DastProfiles', () => { ...@@ -151,6 +160,41 @@ describe('EE - DastProfiles', () => {
); );
}); });
describe.each`
tabName | givenLocationHash
${'Site Profiles'} | ${'site-profiles'}
${'Scanner Profiles'} | ${'scanner-profiles'}
`('with location hash set to "$givenLocationHash"', ({ tabName, givenLocationHash }) => {
beforeEach(() => {
setWindowLocation(`http://foo.com/index#${givenLocationHash}`);
createFullComponent();
});
afterEach(() => {
window.location = originalLocation;
});
it(`has "${tabName}" selected`, () => {
const tab = getTab({
tabName,
selected: true,
});
expect(tab).not.toBe(null);
});
it('updates the browsers URL to contain the selected tab', () => {
window.location.hash = '';
const tab = getTab({ tabName });
createWrapper(tab).trigger('click');
expect(window.location.hash).toBe(givenLocationHash);
});
});
});
describe.each` describe.each`
description | profileType description | profileType
${'Site Profiles List'} | ${'siteProfiles'} ${'Site Profiles List'} | ${'siteProfiles'}
......
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