Commit e33e7ac7 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '327369-update-controls-in-admin-projects-or-groups-access-requests' into 'master'

Add the ability to deep link into group/project member tabs

See merge request gitlab-org/gitlab!64365
parents 24efb0b3 db589f28
...@@ -19,6 +19,11 @@ export default { ...@@ -19,6 +19,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
tabQueryParamValue: {
type: String,
required: false,
default: '',
},
}, },
computed: { computed: {
...mapState({ ...mapState({
...@@ -55,6 +60,6 @@ export default { ...@@ -55,6 +60,6 @@ export default {
errorMessage errorMessage
}}</gl-alert> }}</gl-alert>
<filter-sort-container /> <filter-sort-container />
<members-table /> <members-table :tab-query-param-value="tabQueryParamValue" />
</div> </div>
</template> </template>
...@@ -5,7 +5,11 @@ import { getParameterByName } from '~/lib/utils/common_utils'; ...@@ -5,7 +5,11 @@ import { getParameterByName } from '~/lib/utils/common_utils';
// eslint-disable-next-line import/no-deprecated // eslint-disable-next-line import/no-deprecated
import { setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility'; import { setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { SEARCH_TOKEN_TYPE, SORT_PARAM } from '~/members/constants'; import {
SEARCH_TOKEN_TYPE,
SORT_QUERY_PARAM_NAME,
ACTIVE_TAB_QUERY_PARAM_NAME,
} from '~/members/constants';
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
...@@ -118,10 +122,15 @@ export default { ...@@ -118,10 +122,15 @@ export default {
return accumulator; return accumulator;
}, {}); }, {});
const sortParam = getParameterByName(SORT_PARAM); const sortParamValue = getParameterByName(SORT_QUERY_PARAM_NAME);
const activeTabParamValue = getParameterByName(ACTIVE_TAB_QUERY_PARAM_NAME);
window.location.href = setUrlParams( window.location.href = setUrlParams(
{ ...params, ...(sortParam && { sort: sortParam }) }, {
...params,
...(sortParamValue && { [SORT_QUERY_PARAM_NAME]: sortParamValue }),
...(activeTabParamValue && { [ACTIVE_TAB_QUERY_PARAM_NAME]: activeTabParamValue }),
},
window.location.href, window.location.href,
true, true,
); );
......
...@@ -4,14 +4,15 @@ import { mapState } from 'vuex'; ...@@ -4,14 +4,15 @@ import { mapState } from 'vuex';
// eslint-disable-next-line import/no-deprecated // eslint-disable-next-line import/no-deprecated
import { urlParamsToObject } from '~/lib/utils/url_utility'; import { urlParamsToObject } from '~/lib/utils/url_utility';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { MEMBER_TYPES } from '../constants'; import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES, ACTIVE_TAB_QUERY_PARAM_NAME } from '../constants';
import MembersApp from './app.vue'; import MembersApp from './app.vue';
const countComputed = (state, namespace) => state[namespace]?.pagination?.totalItems || 0; const countComputed = (state, namespace) => state[namespace]?.pagination?.totalItems || 0;
export default { export default {
name: 'MembersTabs', name: 'MembersTabs',
tabs: [ ACTIVE_TAB_QUERY_PARAM_NAME,
TABS: [
{ {
namespace: MEMBER_TYPES.user, namespace: MEMBER_TYPES.user,
title: __('Members'), title: __('Members'),
...@@ -20,19 +21,21 @@ export default { ...@@ -20,19 +21,21 @@ export default {
namespace: MEMBER_TYPES.group, namespace: MEMBER_TYPES.group,
title: __('Groups'), title: __('Groups'),
attrs: { 'data-qa-selector': 'groups_list_tab' }, attrs: { 'data-qa-selector': 'groups_list_tab' },
queryParamValue: TAB_QUERY_PARAM_VALUES.group,
}, },
{ {
namespace: MEMBER_TYPES.invite, namespace: MEMBER_TYPES.invite,
title: __('Invited'), title: __('Invited'),
canManageMembersPermissionsRequired: true, canManageMembersPermissionsRequired: true,
queryParamValue: TAB_QUERY_PARAM_VALUES.invite,
}, },
{ {
namespace: MEMBER_TYPES.accessRequest, namespace: MEMBER_TYPES.accessRequest,
title: __('Access requests'), title: __('Access requests'),
canManageMembersPermissionsRequired: true, canManageMembersPermissionsRequired: true,
queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest,
}, },
], ],
urlParams: [],
components: { MembersApp, GlTabs, GlTab, GlBadge }, components: { MembersApp, GlTabs, GlTab, GlBadge },
inject: ['canManageMembers'], inject: ['canManageMembers'],
data() { data() {
...@@ -60,29 +63,18 @@ export default { ...@@ -60,29 +63,18 @@ export default {
return Object.keys(urlParamsToObject(window.location.search)); return Object.keys(urlParamsToObject(window.location.search));
}, },
activeTabIndexCalculatedFromUrlParams() { activeTabIndexCalculatedFromUrlParams() {
return this.$options.tabs.findIndex(({ namespace }) => { return this.$options.TABS.findIndex(({ namespace }) => {
return this.getTabUrlParams(namespace).some((urlParam) => return this.getTabUrlParams(namespace).some((urlParam) =>
this.urlParams.includes(urlParam), this.urlParams.includes(urlParam),
); );
}); });
}, },
}, },
created() {
if (this.activeTabIndexCalculatedFromUrlParams === -1) {
return;
}
this.selectedTabIndex = this.activeTabIndexCalculatedFromUrlParams;
},
methods: { methods: {
getTabUrlParams(namespace) { getTabUrlParams(namespace) {
const state = this.$store.state[namespace]; const state = this.$store.state[namespace];
const urlParams = []; const urlParams = [];
if (state?.pagination?.paramName) {
urlParams.push(state.pagination.paramName);
}
if (state?.filteredSearchBar?.searchParam) { if (state?.filteredSearchBar?.searchParam) {
urlParams.push(state.filteredSearchBar.searchParam); urlParams.push(state.filteredSearchBar.searchParam);
} }
...@@ -112,14 +104,23 @@ export default { ...@@ -112,14 +104,23 @@ export default {
</script> </script>
<template> <template>
<gl-tabs v-model="selectedTabIndex"> <gl-tabs
<template v-for="(tab, index) in $options.tabs"> v-model="selectedTabIndex"
<gl-tab v-if="showTab(tab, index)" :key="tab.namespace" :title-link-attributes="tab.attrs"> sync-active-tab-with-query-params
:query-param-name="$options.ACTIVE_TAB_QUERY_PARAM_NAME"
>
<template v-for="(tab, index) in $options.TABS">
<gl-tab
v-if="showTab(tab, index)"
:key="tab.namespace"
:title-link-attributes="tab.attrs"
:query-param-value="tab.queryParamValue"
>
<template slot="title"> <template slot="title">
<span>{{ tab.title }}</span> <span>{{ tab.title }}</span>
<gl-badge size="sm" class="gl-tab-counter-badge">{{ getTabCount(tab) }}</gl-badge> <gl-badge size="sm" class="gl-tab-counter-badge">{{ getTabCount(tab) }}</gl-badge>
</template> </template>
<members-app :namespace="tab.namespace" /> <members-app :namespace="tab.namespace" :tab-query-param-value="tab.queryParamValue" />
</gl-tab> </gl-tab>
</template> </template>
</gl-tabs> </gl-tabs>
......
...@@ -5,7 +5,7 @@ import MembersTableCell from 'ee_else_ce/members/components/table/members_table_ ...@@ -5,7 +5,7 @@ import MembersTableCell from 'ee_else_ce/members/components/table/members_table_
import { canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils'; import { canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
import initUserPopovers from '~/user_popovers'; import initUserPopovers from '~/user_popovers';
import { FIELDS } from '../../constants'; import { FIELDS, ACTIVE_TAB_QUERY_PARAM_NAME } from '../../constants';
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue'; import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
import CreatedAt from './created_at.vue'; import CreatedAt from './created_at.vue';
import ExpirationDatepicker from './expiration_datepicker.vue'; import ExpirationDatepicker from './expiration_datepicker.vue';
...@@ -34,6 +34,13 @@ export default { ...@@ -34,6 +34,13 @@ export default {
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'), import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
}, },
inject: ['namespace', 'currentUserId'], inject: ['namespace', 'currentUserId'],
props: {
tabQueryParamValue: {
type: String,
required: false,
default: '',
},
},
computed: { computed: {
...mapState({ ...mapState({
members(state) { members(state) {
...@@ -112,7 +119,15 @@ export default { ...@@ -112,7 +119,15 @@ export default {
paginationLinkGenerator(page) { paginationLinkGenerator(page) {
const { params = {}, paramName } = this.pagination; const { params = {}, paramName } = this.pagination;
return mergeUrlParams({ ...params, [paramName]: page }, window.location.href); return mergeUrlParams(
{
...params,
[ACTIVE_TAB_QUERY_PARAM_NAME]:
this.tabQueryParamValue !== '' ? this.tabQueryParamValue : null,
[paramName]: page,
},
window.location.href,
);
}, },
}, },
}; };
......
...@@ -89,6 +89,12 @@ export const MEMBER_TYPES = { ...@@ -89,6 +89,12 @@ export const MEMBER_TYPES = {
accessRequest: 'accessRequest', accessRequest: 'accessRequest',
}; };
export const TAB_QUERY_PARAM_VALUES = {
group: 'groups',
invite: 'invited',
accessRequest: 'access_requests',
};
export const DAYS_TO_EXPIRE_SOON = 7; export const DAYS_TO_EXPIRE_SOON = 7;
export const LEAVE_MODAL_ID = 'member-leave-modal'; export const LEAVE_MODAL_ID = 'member-leave-modal';
...@@ -97,7 +103,8 @@ export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id'; ...@@ -97,7 +103,8 @@ export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id';
export const SEARCH_TOKEN_TYPE = 'filtered-search-term'; export const SEARCH_TOKEN_TYPE = 'filtered-search-term';
export const SORT_PARAM = 'sort'; export const SORT_QUERY_PARAM_NAME = 'sort';
export const ACTIVE_TAB_QUERY_PARAM_NAME = 'tab';
export const MEMBER_ACCESS_LEVEL_PROPERTY_NAME = 'access_level'; export const MEMBER_ACCESS_LEVEL_PROPERTY_NAME = 'access_level';
......
...@@ -5,7 +5,8 @@ import Vuex from 'vuex'; ...@@ -5,7 +5,8 @@ import Vuex from 'vuex';
import * as commonUtils from '~/lib/utils/common_utils'; import * as commonUtils from '~/lib/utils/common_utils';
import MembersApp from '~/members/components/app.vue'; import MembersApp from '~/members/components/app.vue';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue'; import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import { MEMBER_TYPES } from '~/members/constants'; import MembersTable from '~/members/components/table/members_table.vue';
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
import { RECEIVE_MEMBER_ROLE_ERROR, HIDE_ERROR } from '~/members/store/mutation_types'; import { RECEIVE_MEMBER_ROLE_ERROR, HIDE_ERROR } from '~/members/store/mutation_types';
import mutations from '~/members/store/mutations'; import mutations from '~/members/store/mutations';
...@@ -19,7 +20,7 @@ describe('MembersApp', () => { ...@@ -19,7 +20,7 @@ describe('MembersApp', () => {
const createComponent = (state = {}, options = {}) => { const createComponent = (state = {}, options = {}) => {
store = new Vuex.Store({ store = new Vuex.Store({
modules: { modules: {
[MEMBER_TYPES.user]: { [MEMBER_TYPES.group]: {
namespaced: true, namespaced: true,
state: { state: {
showError: true, showError: true,
...@@ -34,7 +35,8 @@ describe('MembersApp', () => { ...@@ -34,7 +35,8 @@ describe('MembersApp', () => {
wrapper = shallowMount(MembersApp, { wrapper = shallowMount(MembersApp, {
localVue, localVue,
propsData: { propsData: {
namespace: MEMBER_TYPES.user, namespace: MEMBER_TYPES.group,
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.group,
}, },
store, store,
...options, ...options,
...@@ -57,7 +59,7 @@ describe('MembersApp', () => { ...@@ -57,7 +59,7 @@ describe('MembersApp', () => {
it('renders and scrolls to error alert', async () => { it('renders and scrolls to error alert', async () => {
createComponent({ showError: false, errorMessage: '' }); createComponent({ showError: false, errorMessage: '' });
store.commit(`${MEMBER_TYPES.user}/${RECEIVE_MEMBER_ROLE_ERROR}`, { store.commit(`${MEMBER_TYPES.group}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
error: new Error('Network Error'), error: new Error('Network Error'),
}); });
...@@ -77,7 +79,7 @@ describe('MembersApp', () => { ...@@ -77,7 +79,7 @@ describe('MembersApp', () => {
it('does not render and scroll to error alert', async () => { it('does not render and scroll to error alert', async () => {
createComponent(); createComponent();
store.commit(`${MEMBER_TYPES.user}/${HIDE_ERROR}`); store.commit(`${MEMBER_TYPES.group}/${HIDE_ERROR}`);
await nextTick(); await nextTick();
...@@ -103,4 +105,13 @@ describe('MembersApp', () => { ...@@ -103,4 +105,13 @@ describe('MembersApp', () => {
expect(findFilterSortContainer().exists()).toBe(true); expect(findFilterSortContainer().exists()).toBe(true);
}); });
it('renders `MembersTable` component and passes `tabQueryParamValue` prop', () => {
createComponent();
const membersTableComponent = wrapper.findComponent(MembersTable);
expect(membersTableComponent.exists()).toBe(true);
expect(membersTableComponent.props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.group);
});
}); });
...@@ -216,5 +216,17 @@ describe('MembersFilteredSearchBar', () => { ...@@ -216,5 +216,17 @@ describe('MembersFilteredSearchBar', () => {
'https://localhost/?two_factor=enabled&search=foobar&sort=name_asc', 'https://localhost/?two_factor=enabled&search=foobar&sort=name_asc',
); );
}); });
it('adds active tab query param', () => {
window.location.search = '?tab=invited';
createComponent();
findFilteredSearchBar().vm.$emit('onFilter', [
{ type: 'filtered-search-term', value: { data: 'foobar' } },
]);
expect(window.location.href).toBe('https://localhost/?search=foobar&tab=invited');
});
}); });
}); });
import { GlTabs } from '@gitlab/ui';
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import { mountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import MembersApp from '~/members/components/app.vue'; import MembersApp from '~/members/components/app.vue';
import MembersTabs from '~/members/components/members_tabs.vue'; import MembersTabs from '~/members/components/members_tabs.vue';
import { MEMBER_TYPES } from '~/members/constants'; import {
MEMBER_TYPES,
TAB_QUERY_PARAM_VALUES,
ACTIVE_TAB_QUERY_PARAM_NAME,
} from '~/members/constants';
import { pagination } from '../mock_data'; import { pagination } from '../mock_data';
describe('MembersTabs', () => { describe('MembersTabs', () => {
...@@ -93,6 +98,18 @@ describe('MembersTabs', () => { ...@@ -93,6 +98,18 @@ describe('MembersTabs', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders `GlTabs` with `syncActiveTabWithQueryParams` and `queryParamName` props set', async () => {
await createComponent();
const glTabsComponent = wrapper.findComponent(GlTabs);
expect(glTabsComponent.exists()).toBe(true);
expect(glTabsComponent.props()).toMatchObject({
syncActiveTabWithQueryParams: true,
queryParamName: ACTIVE_TAB_QUERY_PARAM_NAME,
});
});
describe('when tabs have a count', () => { describe('when tabs have a count', () => {
it('renders tabs with count', async () => { it('renders tabs with count', async () => {
await createComponent(); await createComponent();
...@@ -106,7 +123,7 @@ describe('MembersTabs', () => { ...@@ -106,7 +123,7 @@ describe('MembersTabs', () => {
expect(findActiveTab().text()).toContain('Members'); expect(findActiveTab().text()).toContain('Members');
}); });
it('renders `MembersApp` and passes `namespace` prop', async () => { it('renders `MembersApp` and passes `namespace` and `tabQueryParamValue` props', async () => {
await createComponent(); await createComponent();
const membersApps = wrapper.findAllComponents(MembersApp).wrappers; const membersApps = wrapper.findAllComponents(MembersApp).wrappers;
...@@ -115,6 +132,10 @@ describe('MembersTabs', () => { ...@@ -115,6 +132,10 @@ describe('MembersTabs', () => {
expect(membersApps[1].props('namespace')).toBe(MEMBER_TYPES.group); expect(membersApps[1].props('namespace')).toBe(MEMBER_TYPES.group);
expect(membersApps[2].props('namespace')).toBe(MEMBER_TYPES.invite); expect(membersApps[2].props('namespace')).toBe(MEMBER_TYPES.invite);
expect(membersApps[3].props('namespace')).toBe(MEMBER_TYPES.accessRequest); expect(membersApps[3].props('namespace')).toBe(MEMBER_TYPES.accessRequest);
expect(membersApps[1].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.group);
expect(membersApps[2].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.invite);
expect(membersApps[3].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.accessRequest);
}); });
}); });
...@@ -127,56 +148,16 @@ describe('MembersTabs', () => { ...@@ -127,56 +148,16 @@ describe('MembersTabs', () => {
expect(findTabByText('Invited')).toBeUndefined(); expect(findTabByText('Invited')).toBeUndefined();
expect(findTabByText('Access requests')).toBeUndefined(); expect(findTabByText('Access requests')).toBeUndefined();
}); });
});
describe('when url param matches `filteredSearchBar.searchParam`', () => { describe('when url param matches `filteredSearchBar.searchParam`', () => {
beforeEach(() => { beforeEach(() => {
window.location.search = '?search_groups=foo+bar'; window.location.search = '?search_groups=foo+bar';
});
const expectGroupsTabActive = () => {
expect(findActiveTab().text()).toContain('Groups');
};
describe('when tab has a count', () => {
it('sets tab that corresponds to search param as active tab', async () => {
await createComponent();
expectGroupsTabActive();
}); });
});
describe('when tab does not have a count', () => {
it('sets tab that corresponds to search param as active tab', async () => {
await createComponent({ totalItems: 0 });
expectGroupsTabActive();
});
});
});
describe('when url param matches `pagination.paramName`', () => {
beforeEach(() => {
window.location.search = '?invited_page=2';
});
const expectInvitedTabActive = () => {
expect(findActiveTab().text()).toContain('Invited');
};
describe('when tab has a count', () => {
it('sets tab that corresponds to pagination param as active tab', async () => {
await createComponent();
expectInvitedTabActive();
});
});
describe('when tab does not have a count', () => { it('shows tab that corresponds to search param', async () => {
it('sets tab that corresponds to pagination param as active tab', async () => {
await createComponent({ totalItems: 0 }); await createComponent({ totalItems: 0 });
expectInvitedTabActive(); expect(findTabByText('Groups')).not.toBeUndefined();
}); });
}); });
}); });
......
...@@ -15,7 +15,7 @@ import MemberAvatar from '~/members/components/table/member_avatar.vue'; ...@@ -15,7 +15,7 @@ import MemberAvatar from '~/members/components/table/member_avatar.vue';
import MemberSource from '~/members/components/table/member_source.vue'; import MemberSource from '~/members/components/table/member_source.vue';
import MembersTable from '~/members/components/table/members_table.vue'; import MembersTable from '~/members/components/table/members_table.vue';
import RoleDropdown from '~/members/components/table/role_dropdown.vue'; import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants'; import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
import * as initUserPopovers from '~/user_popovers'; import * as initUserPopovers from '~/user_popovers';
import { import {
member as memberMock, member as memberMock,
...@@ -34,7 +34,7 @@ describe('MembersTable', () => { ...@@ -34,7 +34,7 @@ describe('MembersTable', () => {
const createStore = (state = {}) => { const createStore = (state = {}) => {
return new Vuex.Store({ return new Vuex.Store({
modules: { modules: {
[MEMBER_TYPES.user]: { [MEMBER_TYPES.invite]: {
namespaced: true, namespaced: true,
state: { state: {
members: [], members: [],
...@@ -54,11 +54,14 @@ describe('MembersTable', () => { ...@@ -54,11 +54,14 @@ describe('MembersTable', () => {
const createComponent = (state, provide = {}) => { const createComponent = (state, provide = {}) => {
wrapper = mount(MembersTable, { wrapper = mount(MembersTable, {
localVue, localVue,
propsData: {
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.invite,
},
store: createStore(state), store: createStore(state),
provide: { provide: {
sourceId: 1, sourceId: 1,
currentUserId: 1, currentUserId: 1,
namespace: MEMBER_TYPES.user, namespace: MEMBER_TYPES.invite,
...provide, ...provide,
}, },
stubs: [ stubs: [
...@@ -74,7 +77,7 @@ describe('MembersTable', () => { ...@@ -74,7 +77,7 @@ describe('MembersTable', () => {
}); });
}; };
const url = 'https://localhost/foo-bar/-/project_members'; const url = 'https://localhost/foo-bar/-/project_members?tab=invited';
const getByText = (text, options) => const getByText = (text, options) =>
createWrapper(getByTextHelper(wrapper.element, text, options)); createWrapper(getByTextHelper(wrapper.element, text, options));
...@@ -92,7 +95,7 @@ describe('MembersTable', () => { ...@@ -92,7 +95,7 @@ describe('MembersTable', () => {
const expectCorrectLinkToPage2 = () => { const expectCorrectLinkToPage2 = () => {
expect(findPagination().findByText('2', { selector: 'a' }).attributes('href')).toBe( expect(findPagination().findByText('2', { selector: 'a' }).attributes('href')).toBe(
`${url}?page=2`, `${url}&invited_members_page=2`,
); );
}; };
...@@ -271,7 +274,7 @@ describe('MembersTable', () => { ...@@ -271,7 +274,7 @@ describe('MembersTable', () => {
currentPage: 1, currentPage: 1,
perPage: 5, perPage: 5,
totalItems: 10, totalItems: 10,
paramName: 'page', paramName: 'invited_members_page',
}, },
}); });
...@@ -279,14 +282,14 @@ describe('MembersTable', () => { ...@@ -279,14 +282,14 @@ describe('MembersTable', () => {
}); });
it('removes any url params defined as `null` in the `params` attribute', () => { it('removes any url params defined as `null` in the `params` attribute', () => {
window.location = new URL(`${url}?search_groups=foo`); window.location = new URL(`${url}&search_groups=foo`);
createComponent({ createComponent({
pagination: { pagination: {
currentPage: 1, currentPage: 1,
perPage: 5, perPage: 5,
totalItems: 10, totalItems: 10,
paramName: 'page', paramName: 'invited_members_page',
params: { search_groups: null }, params: { search_groups: null },
}, },
}); });
......
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