Commit 964c6c08 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch '324680-group-project-members-migrate-to-namespaced-vuex-modules' into 'master'

Refactor to using Vuex modules for project/group members views

See merge request gitlab-org/gitlab!58828
parents 868e69fb 90eeb34e
......@@ -12,6 +12,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
memberId: {
type: Number,
......@@ -19,7 +20,11 @@ export default {
},
},
computed: {
...mapState(['memberPath']),
...mapState({
memberPath(state) {
return state[this.namespace].memberPath;
},
}),
approvePath() {
return this.memberPath.replace(/:id$/, `${this.memberId}/approve_access_request`);
},
......
......@@ -12,6 +12,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
groupLink: {
type: Object,
......@@ -19,7 +20,11 @@ export default {
},
},
methods: {
...mapActions(['showRemoveGroupLinkModal']),
...mapActions({
showRemoveGroupLinkModal(dispatch, payload) {
return dispatch(`${this.namespace}/showRemoveGroupLinkModal`, payload);
},
}),
},
};
</script>
......
......@@ -8,6 +8,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
memberId: {
type: Number,
......@@ -43,7 +44,11 @@ export default {
},
},
computed: {
...mapState(['memberPath']),
...mapState({
memberPath(state) {
return state[this.namespace].memberPath;
},
}),
computedMemberPath() {
return this.memberPath.replace(':id', this.memberId);
},
......
......@@ -12,6 +12,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
memberId: {
type: Number,
......@@ -19,7 +20,11 @@ export default {
},
},
computed: {
...mapState(['memberPath']),
...mapState({
memberPath(state) {
return state[this.namespace].memberPath;
},
}),
resendPath() {
return this.memberPath.replace(/:id$/, `${this.memberId}/resend_invite`);
},
......
......@@ -9,8 +9,16 @@ import MembersTable from './table/members_table.vue';
export default {
name: 'MembersApp',
components: { MembersTable, FilterSortContainer, GlAlert },
inject: ['namespace'],
computed: {
...mapState(['showError', 'errorMessage']),
...mapState({
showError(state) {
return state[this.namespace].showError;
},
errorMessage(state) {
return state[this.namespace].errorMessage;
},
}),
},
watch: {
showError(value) {
......@@ -23,7 +31,9 @@ export default {
},
methods: {
...mapMutations({
hideError: HIDE_ERROR,
hideError(commit) {
return commit(`${this.namespace}/${HIDE_ERROR}`);
},
}),
},
};
......
......@@ -6,8 +6,16 @@ import SortDropdown from './sort_dropdown.vue';
export default {
name: 'FilterSortContainer',
components: { MembersFilteredSearchBar, SortDropdown },
inject: ['namespace'],
computed: {
...mapState(['filteredSearchBar', 'tableSortableFields']),
...mapState({
filteredSearchBar(state) {
return state[this.namespace].filteredSearchBar;
},
tableSortableFields(state) {
return state[this.namespace].tableSortableFields;
},
}),
showContainer() {
return this.filteredSearchBar.show || this.showSortDropdown;
},
......
......@@ -37,14 +37,18 @@ export default {
],
},
],
inject: ['sourceId', 'canManageMembers'],
inject: ['namespace', 'sourceId', 'canManageMembers'],
data() {
return {
initialFilterValue: [],
};
},
computed: {
...mapState(['filteredSearchBar']),
...mapState({
filteredSearchBar(state) {
return state[this.namespace].filteredSearchBar;
},
}),
tokens() {
return this.$options.availableTokens.filter((token) => {
if (
......
......@@ -8,8 +8,16 @@ import { parseSortParam, buildSortHref } from '~/members/utils';
export default {
name: 'SortDropdown',
components: { GlSorting, GlSortingItem },
inject: ['namespace'],
computed: {
...mapState(['tableSortableFields', 'filteredSearchBar']),
...mapState({
tableSortableFields(state) {
return state[this.namespace].tableSortableFields;
},
filteredSearchBar(state) {
return state[this.namespace].filteredSearchBar;
},
}),
sort() {
return parseSortParam(this.tableSortableFields);
},
......
......@@ -23,6 +23,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
member: {
type: Object,
......@@ -30,7 +31,11 @@ export default {
},
},
computed: {
...mapState(['memberPath']),
...mapState({
memberPath(state) {
return state[this.namespace].memberPath;
},
}),
leavePath() {
return this.memberPath.replace(/:id$/, 'leave');
},
......
......@@ -22,8 +22,19 @@ export default {
},
modalId: REMOVE_GROUP_LINK_MODAL_ID,
components: { GlModal, GlSprintf, GlForm },
inject: ['namespace'],
computed: {
...mapState(['memberPath', 'groupLinkToRemove', 'removeGroupLinkModalVisible']),
...mapState({
memberPath(state) {
return state[this.namespace].memberPath;
},
groupLinkToRemove(state) {
return state[this.namespace].groupLinkToRemove;
},
removeGroupLinkModalVisible(state) {
return state[this.namespace].removeGroupLinkModalVisible;
},
}),
groupLinkPath() {
return this.memberPath.replace(/:id$/, this.groupLinkToRemove?.id);
},
......@@ -35,7 +46,11 @@ export default {
},
},
methods: {
...mapActions(['hideRemoveGroupLinkModal']),
...mapActions({
hideRemoveGroupLinkModal(dispatch) {
return dispatch(`${this.namespace}/hideRemoveGroupLinkModal`);
},
}),
handlePrimary() {
this.$refs.form.$el.submit();
},
......
......@@ -7,6 +7,7 @@ import { s__ } from '~/locale';
export default {
name: 'ExpirationDatepicker',
components: { GlDatepicker },
inject: ['namespace'],
props: {
member: {
type: Object,
......@@ -46,7 +47,11 @@ export default {
}
},
methods: {
...mapActions(['updateMemberExpiration']),
...mapActions({
updateMemberExpiration(dispatch, payload) {
return dispatch(`${this.namespace}/updateMemberExpiration`, payload);
},
}),
handleInput(date) {
this.busy = true;
this.updateMemberExpiration({
......
......@@ -31,9 +31,19 @@ export default {
LdapOverrideConfirmationModal: () =>
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
},
inject: ['currentUserId'],
inject: ['namespace', 'currentUserId'],
computed: {
...mapState(['members', 'tableFields', 'tableAttrs']),
...mapState({
members(state) {
return state[this.namespace].members;
},
tableFields(state) {
return state[this.namespace].tableFields;
},
tableAttrs(state) {
return state[this.namespace].tableAttrs;
},
}),
filteredFields() {
return FIELDS.filter(
(field) => this.tableFields.includes(field.key) && this.showField(field),
......
......@@ -11,6 +11,7 @@ export default {
GlDropdownItem,
LdapDropdownItem: () => import('ee_component/members/components/ldap/ldap_dropdown_item.vue'),
},
inject: ['namespace'],
props: {
member: {
type: Object,
......@@ -44,7 +45,11 @@ export default {
}
},
methods: {
...mapActions(['updateMemberRole']),
...mapActions({
updateMemberRole(dispatch, payload) {
return dispatch(`${this.namespace}/updateMemberRole`, payload);
},
}),
handleSelect(value, name) {
if (value === this.member.accessLevel.integerValue) {
return;
......
......@@ -8,6 +8,7 @@ import membersStore from './store';
export const initMembersApp = (
el,
{
namespace,
tableFields = [],
tableAttrs = {},
tableSortableFields = [],
......@@ -24,22 +25,25 @@ export const initMembersApp = (
const { sourceId, canManageMembers, ...vuexStoreAttributes } = parseDataAttributes(el);
const store = new Vuex.Store(
membersStore({
...vuexStoreAttributes,
tableFields,
tableAttrs,
tableSortableFields,
requestFormatter,
filteredSearchBar,
}),
);
const store = new Vuex.Store({
modules: {
[namespace]: membersStore({
...vuexStoreAttributes,
tableFields,
tableAttrs,
tableSortableFields,
requestFormatter,
filteredSearchBar,
}),
},
});
return new Vue({
el,
components: { App },
store,
provide: {
namespace,
currentUserId: gon.current_user_id || null,
sourceId,
canManageMembers,
......
......@@ -3,6 +3,7 @@ import mutations from 'ee_else_ce/members/store/mutations';
import createState from 'ee_else_ce/members/store/state';
export default (initialState) => ({
namespaced: true,
state: createState(initialState),
actions,
mutations,
......
......@@ -8,6 +8,7 @@ import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigg
import { s__ } from '~/locale';
import memberExpirationDate from '~/member_expiration_date';
import { initMembersApp } from '~/members';
import { MEMBER_TYPES } from '~/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
import UsersSelect from '~/users_select';
import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
......@@ -29,6 +30,7 @@ function mountRemoveMemberModal() {
const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-group-members-list'), {
namespace: MEMBER_TYPES.user,
tableFields: SHARED_FIELDS.concat(['source', 'granted']),
tableAttrs: { tr: { 'data-qa-selector': 'member_row' } },
tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'],
......@@ -43,6 +45,7 @@ initMembersApp(document.querySelector('.js-group-members-list'), {
});
initMembersApp(document.querySelector('.js-group-group-links-list'), {
namespace: MEMBER_TYPES.group,
tableFields: SHARED_FIELDS.concat('granted'),
tableAttrs: {
table: { 'data-qa-selector': 'groups_list' },
......@@ -51,6 +54,7 @@ initMembersApp(document.querySelector('.js-group-group-links-list'), {
requestFormatter: groupLinkRequestFormatter,
});
initMembersApp(document.querySelector('.js-group-invited-members-list'), {
namespace: MEMBER_TYPES.invite,
tableFields: SHARED_FIELDS.concat('invited'),
requestFormatter: groupMemberRequestFormatter,
filteredSearchBar: {
......@@ -62,6 +66,7 @@ initMembersApp(document.querySelector('.js-group-invited-members-list'), {
},
});
initMembersApp(document.querySelector('.js-group-access-requests-list'), {
namespace: MEMBER_TYPES.accessRequest,
tableFields: SHARED_FIELDS.concat('requested'),
requestFormatter: groupMemberRequestFormatter,
});
......
......@@ -7,6 +7,7 @@ import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigg
import { s__ } from '~/locale';
import memberExpirationDate from '~/member_expiration_date';
import { initMembersApp } from '~/members';
import { MEMBER_TYPES } from '~/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
import { projectMemberRequestFormatter } from '~/projects/members/utils';
import UsersSelect from '~/users_select';
......@@ -42,6 +43,7 @@ new UsersSelect(); // eslint-disable-line no-new
const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-project-members-list'), {
namespace: MEMBER_TYPES.user,
tableFields: SHARED_FIELDS.concat(['source', 'granted']),
tableAttrs: { tr: { 'data-qa-selector': 'member_row' } },
tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'],
......@@ -56,6 +58,7 @@ initMembersApp(document.querySelector('.js-project-members-list'), {
});
initMembersApp(document.querySelector('.js-project-group-links-list'), {
namespace: MEMBER_TYPES.group,
tableFields: SHARED_FIELDS.concat('granted'),
tableAttrs: {
table: { 'data-qa-selector': 'groups_list' },
......@@ -72,11 +75,13 @@ initMembersApp(document.querySelector('.js-project-group-links-list'), {
});
initMembersApp(document.querySelector('.js-project-invited-members-list'), {
namespace: MEMBER_TYPES.invite,
tableFields: SHARED_FIELDS.concat('invited'),
requestFormatter: projectMemberRequestFormatter,
});
initMembersApp(document.querySelector('.js-project-access-requests-list'), {
namespace: MEMBER_TYPES.accessRequest,
tableFields: SHARED_FIELDS.concat('requested'),
requestFormatter: projectMemberRequestFormatter,
});
......@@ -6,6 +6,7 @@ import { s__ } from '~/locale';
export default {
name: 'LdapDropdownItem',
components: { GlDropdownItem, GlDropdownDivider },
inject: ['namespace'],
props: {
memberId: {
type: Number,
......@@ -13,7 +14,11 @@ export default {
},
},
methods: {
...mapActions(['updateLdapOverride']),
...mapActions({
updateLdapOverride(dispatch, payload) {
return dispatch(`${this.namespace}/updateLdapOverride`, payload);
},
}),
handleClick() {
this.updateLdapOverride({ memberId: this.memberId, override: false })
.then(() => {
......
......@@ -12,6 +12,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['namespace'],
props: {
member: {
type: Object,
......@@ -19,7 +20,11 @@ export default {
},
},
methods: {
...mapActions(['showLdapOverrideConfirmationModal']),
...mapActions({
showLdapOverrideConfirmationModal(dispatch, payload) {
return dispatch(`${this.namespace}/showLdapOverrideConfirmationModal`, payload);
},
}),
},
};
</script>
......
......@@ -18,13 +18,21 @@ export default {
},
modalId: LDAP_OVERRIDE_CONFIRMATION_MODAL_ID,
components: { GlModal, GlSprintf },
inject: ['namespace'],
data() {
return {
busy: false,
};
},
computed: {
...mapState(['memberToOverride', 'ldapOverrideConfirmationModalVisible']),
...mapState({
memberToOverride(state) {
return state[this.namespace].memberToOverride;
},
ldapOverrideConfirmationModalVisible(state) {
return state[this.namespace].ldapOverrideConfirmationModalVisible;
},
}),
actionPrimary() {
return {
text: this.$options.i18n.editPermissions,
......@@ -36,7 +44,14 @@ export default {
},
},
methods: {
...mapActions(['updateLdapOverride', 'hideLdapOverrideConfirmationModal']),
...mapActions({
updateLdapOverride(dispatch, payload) {
return dispatch(`${this.namespace}/updateLdapOverride`, payload);
},
hideLdapOverrideConfirmationModal(dispatch) {
return dispatch(`${this.namespace}/hideLdapOverrideConfirmationModal`);
},
}),
handlePrimary() {
this.busy = true;
......
......@@ -3,12 +3,16 @@ import LdapOverrideButton from 'ee/members/components/ldap/ldap_override_button.
import waitForPromises from 'helpers/wait_for_promises';
import { member } from 'jest/members/mock_data';
import UserActionButtons from '~/members/components/action_buttons/user_action_buttons.vue';
import { MEMBER_TYPES } from '~/members/constants';
describe('UserActionButtons', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(UserActionButtons, {
provide: {
namespace: MEMBER_TYPES.user,
},
propsData: {
member,
isCurrentUser: false,
......
......@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import LdapDropdownItem from 'ee/members/components/ldap/ldap_dropdown_item.vue';
import waitForPromises from 'helpers/wait_for_promises';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -19,7 +20,14 @@ describe('LdapDropdownItem', () => {
updateLdapOverride: jest.fn(() => Promise.resolve()),
};
return new Vuex.Store({ actions });
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
actions,
},
},
});
};
const createComponent = (propsData = {}) => {
......@@ -30,6 +38,9 @@ describe('LdapDropdownItem', () => {
},
localVue,
store: createStore(),
provide: {
namespace: MEMBER_TYPES.user,
},
mocks: {
$toast,
},
......
......@@ -4,6 +4,7 @@ import Vuex from 'vuex';
import LdapOverrideButton from 'ee/members/components/ldap/ldap_override_button.vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { member } from 'jest/members/mock_data';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -17,7 +18,14 @@ describe('LdapOverrideButton', () => {
showLdapOverrideConfirmationModal: jest.fn(),
};
return new Vuex.Store({ actions });
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
actions,
},
},
});
};
const createComponent = (propsData = {}) => {
......@@ -28,6 +36,9 @@ describe('LdapOverrideButton', () => {
...propsData,
},
store: createStore(),
provide: {
namespace: MEMBER_TYPES.user,
},
directives: {
GlTooltip: createMockDirective(),
},
......
......@@ -7,6 +7,7 @@ import LdapOverrideConfirmationModal from 'ee/members/components/ldap/ldap_overr
import { LDAP_OVERRIDE_CONFIRMATION_MODAL_ID } from 'ee/members/constants';
import waitForPromises from 'helpers/wait_for_promises';
import { member } from 'jest/members/mock_data';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -31,12 +32,17 @@ describe('LdapOverrideConfirmationModal', () => {
};
return new Vuex.Store({
state: {
memberToOverride: member,
ldapOverrideConfirmationModalVisible: true,
...state,
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
memberToOverride: member,
ldapOverrideConfirmationModalVisible: true,
...state,
},
actions,
},
},
actions,
});
};
......@@ -44,6 +50,9 @@ describe('LdapOverrideConfirmationModal', () => {
wrapper = mount(LdapOverrideConfirmationModal, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
},
attrs: {
static: true,
},
......
......@@ -2,12 +2,16 @@ import { GlDatepicker } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { member } from 'jest/members/mock_data';
import ExpirationDatepicker from '~/members/components/table/expiration_datepicker.vue';
import { MEMBER_TYPES } from '~/members/constants';
describe('ExpirationDatepicker', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = mount(ExpirationDatepicker, {
provide: {
namespace: MEMBER_TYPES.user,
},
propsData,
});
};
......
......@@ -3,6 +3,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import Vuex from 'vuex';
import { member as memberMock, directMember, members } from 'jest/members/mock_data';
import MembersTable from '~/members/components/table/members_table.vue';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -12,14 +13,19 @@ describe('MemberList', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
members: [],
tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
members: [],
tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
...state,
},
},
...state,
},
});
};
......@@ -31,6 +37,7 @@ describe('MemberList', () => {
provide: {
sourceId: 1,
currentUserId: 1,
namespace: MEMBER_TYPES.user,
},
stubs: [
'member-avatar',
......
......@@ -4,12 +4,16 @@ import LdapDropdownItem from 'ee/members/components/ldap/ldap_dropdown_item.vue'
import waitForPromises from 'helpers/wait_for_promises';
import { member } from 'jest/members/mock_data';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
describe('RoleDropdown', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(RoleDropdown, {
provide: {
namespace: MEMBER_TYPES.user,
},
propsData: {
member,
permissions: {},
......
import { membersJsonString } from 'jest/members/mock_data';
import { MEMBER_TYPES } from '~/members/constants';
import { initMembersApp } from '~/members/index';
describe('initMembersApp', () => {
......@@ -6,7 +7,9 @@ describe('initMembersApp', () => {
let vm;
const createVm = () => {
vm = initMembersApp(el, {});
vm = initMembersApp(el, {
namespace: MEMBER_TYPES.user,
});
};
beforeEach(() => {
......@@ -24,7 +27,7 @@ describe('initMembersApp', () => {
it('sets `ldapOverridePath` in Vuex store', () => {
createVm();
expect(vm.$store.state.ldapOverridePath).toBe(
expect(vm.$store.state[MEMBER_TYPES.user].ldapOverridePath).toBe(
'/groups/ldap-group/-/group_members/:id/override',
);
});
......
......@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ApproveAccessRequestButton from '~/members/components/action_buttons/approve_access_request_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
......@@ -14,9 +15,14 @@ describe('ApproveAccessRequestButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
modules: {
[MEMBER_TYPES.accessRequest]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
},
},
},
});
};
......@@ -25,6 +31,9 @@ describe('ApproveAccessRequestButton', () => {
wrapper = shallowMount(ApproveAccessRequestButton, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.accessRequest,
},
propsData: {
memberId: 1,
...propsData,
......
......@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import RemoveGroupLinkButton from '~/members/components/action_buttons/remove_group_link_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { group } from '../../mock_data';
const localVue = createLocalVue();
......@@ -17,7 +18,12 @@ describe('RemoveGroupLinkButton', () => {
const createStore = () => {
return new Vuex.Store({
actions,
modules: {
[MEMBER_TYPES.group]: {
namespaced: true,
actions,
},
},
});
};
......@@ -25,6 +31,9 @@ describe('RemoveGroupLinkButton', () => {
wrapper = mount(RemoveGroupLinkButton, {
localVue,
store: createStore(),
provide: {
namespace: MEMBER_TYPES.group,
},
propsData: {
groupLink: group,
},
......
......@@ -2,6 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -11,9 +12,14 @@ describe('RemoveMemberButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
},
},
},
});
};
......@@ -22,6 +28,9 @@ describe('RemoveMemberButton', () => {
wrapper = shallowMount(RemoveMemberButton, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
},
propsData: {
memberId: 1,
memberType: 'GroupMember',
......
......@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ResendInviteButton from '~/members/components/action_buttons/resend_invite_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
......@@ -14,9 +15,14 @@ describe('ResendInviteButton', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
modules: {
[MEMBER_TYPES.invite]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
},
},
},
});
};
......@@ -25,6 +31,9 @@ describe('ResendInviteButton', () => {
wrapper = shallowMount(ResendInviteButton, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.invite,
},
propsData: {
memberId: 1,
...propsData,
......
......@@ -5,6 +5,7 @@ import Vuex from 'vuex';
import * as commonUtils from '~/lib/utils/common_utils';
import MembersApp from '~/members/components/app.vue';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { RECEIVE_MEMBER_ROLE_ERROR, HIDE_ERROR } from '~/members/store/mutation_types';
import mutations from '~/members/store/mutations';
......@@ -17,16 +18,24 @@ describe('MembersApp', () => {
const createComponent = (state = {}, options = {}) => {
store = new Vuex.Store({
state: {
showError: true,
errorMessage: 'Something went wrong, please try again.',
...state,
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
showError: true,
errorMessage: 'Something went wrong, please try again.',
...state,
},
mutations,
},
},
mutations,
});
wrapper = shallowMount(MembersApp, {
localVue,
provide: {
namespace: MEMBER_TYPES.user,
},
store,
...options,
});
......@@ -48,7 +57,9 @@ describe('MembersApp', () => {
it('renders and scrolls to error alert', async () => {
createComponent({ showError: false, errorMessage: '' });
store.commit(RECEIVE_MEMBER_ROLE_ERROR, { error: new Error('Network Error') });
store.commit(`${MEMBER_TYPES.user}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
error: new Error('Network Error'),
});
await nextTick();
......@@ -66,7 +77,7 @@ describe('MembersApp', () => {
it('does not render and scroll to error alert', async () => {
createComponent();
store.commit(HIDE_ERROR);
store.commit(`${MEMBER_TYPES.user}/${HIDE_ERROR}`);
await nextTick();
......
......@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue';
import SortDropdown from '~/members/components/filter_sort/sort_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -12,22 +13,30 @@ describe('FilterSortContainer', () => {
const createComponent = (state) => {
const store = new Vuex.Store({
state: {
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
},
tableSortableFields: ['account'],
...state,
},
},
tableSortableFields: ['account'],
...state,
},
});
wrapper = shallowMount(FilterSortContainer, {
localVue,
store,
provide: {
namespace: MEMBER_TYPES.user,
},
});
};
......
......@@ -2,6 +2,7 @@ import { GlFilteredSearchToken } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue';
import { MEMBER_TYPES } from '~/members/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
const localVue = createLocalVue();
......@@ -12,15 +13,20 @@ describe('MembersFilteredSearchBar', () => {
const createComponent = ({ state = {}, provide = {} } = {}) => {
const store = new Vuex.Store({
state: {
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
},
...state,
},
},
...state,
},
});
......@@ -29,6 +35,7 @@ describe('MembersFilteredSearchBar', () => {
provide: {
sourceId: 1,
canManageMembers: true,
namespace: MEMBER_TYPES.user,
...provide,
},
store,
......
......@@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import * as urlUtilities from '~/lib/utils/url_utility';
import SortDropdown from '~/members/components/filter_sort/sort_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -14,16 +15,21 @@ describe('SortDropdown', () => {
const createComponent = (state) => {
const store = new Vuex.Store({
state: {
tableSortableFields: ['account', 'granted', 'expires', 'maxRole', 'lastSignIn'],
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
tableSortableFields: ['account', 'granted', 'expires', 'maxRole', 'lastSignIn'],
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
searchParam: 'search',
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
},
...state,
},
},
...state,
},
});
......@@ -31,6 +37,7 @@ describe('SortDropdown', () => {
localVue,
provide: {
sourceId: 1,
namespace: MEMBER_TYPES.user,
},
store,
});
......
......@@ -4,7 +4,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import { nextTick } from 'vue';
import Vuex from 'vuex';
import LeaveModal from '~/members/components/modals/leave_modal.vue';
import { LEAVE_MODAL_ID } from '~/members/constants';
import { LEAVE_MODAL_ID, MEMBER_TYPES } from '~/members/constants';
import { member } from '../../mock_data';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
......@@ -17,9 +17,14 @@ describe('LeaveModal', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
},
},
},
});
};
......@@ -28,6 +33,9 @@ describe('LeaveModal', () => {
wrapper = mount(LeaveModal, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.user,
},
propsData: {
member,
...propsData,
......
......@@ -4,7 +4,7 @@ import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
import { nextTick } from 'vue';
import Vuex from 'vuex';
import RemoveGroupLinkModal from '~/members/components/modals/remove_group_link_modal.vue';
import { REMOVE_GROUP_LINK_MODAL_ID } from '~/members/constants';
import { REMOVE_GROUP_LINK_MODAL_ID, MEMBER_TYPES } from '~/members/constants';
import { group } from '../../mock_data';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
......@@ -21,13 +21,18 @@ describe('RemoveGroupLinkModal', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
memberPath: '/groups/foo-bar/-/group_links/:id',
groupLinkToRemove: group,
removeGroupLinkModalVisible: true,
...state,
modules: {
[MEMBER_TYPES.group]: {
namespaced: true,
state: {
memberPath: '/groups/foo-bar/-/group_links/:id',
groupLinkToRemove: group,
removeGroupLinkModalVisible: true,
...state,
},
actions,
},
},
actions,
});
};
......@@ -35,6 +40,9 @@ describe('RemoveGroupLinkModal', () => {
wrapper = mount(RemoveGroupLinkModal, {
localVue,
store: createStore(state),
provide: {
namespace: MEMBER_TYPES.group,
},
attrs: {
static: true,
},
......
......@@ -5,6 +5,7 @@ import Vuex from 'vuex';
import { useFakeDate } from 'helpers/fake_date';
import waitForPromises from 'helpers/wait_for_promises';
import ExpirationDatepicker from '~/members/components/table/expiration_datepicker.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { member } from '../../mock_data';
const localVue = createLocalVue();
......@@ -31,7 +32,11 @@ describe('ExpirationDatepicker', () => {
),
};
return new Vuex.Store({ actions });
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: { namespaced: true, actions },
},
});
};
const createComponent = (propsData = {}) => {
......@@ -41,6 +46,9 @@ describe('ExpirationDatepicker', () => {
permissions: { canUpdate: true },
...propsData,
},
provide: {
namespace: MEMBER_TYPES.user,
},
localVue,
store: createStore(),
mocks: {
......
......@@ -14,6 +14,7 @@ import MemberAvatar from '~/members/components/table/member_avatar.vue';
import MemberSource from '~/members/components/table/member_source.vue';
import MembersTable from '~/members/components/table/members_table.vue';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
import * as initUserPopovers from '~/user_popovers';
import { member as memberMock, directMember, invite, accessRequest } from '../../mock_data';
......@@ -25,14 +26,19 @@ describe('MembersTable', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
state: {
members: [],
tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
modules: {
[MEMBER_TYPES.user]: {
namespaced: true,
state: {
members: [],
tableFields: [],
tableAttrs: {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
...state,
},
},
...state,
},
});
};
......@@ -44,6 +50,7 @@ describe('MembersTable', () => {
provide: {
sourceId: 1,
currentUserId: 1,
namespace: MEMBER_TYPES.user,
...provide,
},
stubs: [
......
......@@ -7,6 +7,7 @@ import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
import { BV_DROPDOWN_SHOW } from '~/lib/utils/constants';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { member } from '../../mock_data';
const localVue = createLocalVue();
......@@ -24,11 +25,18 @@ describe('RoleDropdown', () => {
updateMemberRole: jest.fn(() => Promise.resolve()),
};
return new Vuex.Store({ actions });
return new Vuex.Store({
modules: {
[MEMBER_TYPES.user]: { namespaced: true, actions },
},
});
};
const createComponent = (propsData = {}) => {
wrapper = mount(RoleDropdown, {
provide: {
namespace: MEMBER_TYPES.user,
},
propsData: {
member,
permissions: {},
......
import { createWrapper } from '@vue/test-utils';
import MembersApp from '~/members/components/app.vue';
import { MEMBER_TYPES } from '~/members/constants';
import { initMembersApp } from '~/members/index';
import { membersJsonString, members } from './mock_data';
......@@ -10,6 +11,7 @@ describe('initMembersApp', () => {
const setup = () => {
vm = initMembersApp(el, {
namespace: MEMBER_TYPES.user,
tableFields: ['account'],
tableAttrs: { table: { 'data-qa-selector': 'members_list' } },
tableSortableFields: ['account'],
......@@ -45,42 +47,46 @@ describe('initMembersApp', () => {
it('parses and sets `members` in Vuex store', () => {
setup();
expect(vm.$store.state.members).toEqual(members);
expect(vm.$store.state[MEMBER_TYPES.user].members).toEqual(members);
});
it('sets `tableFields` in Vuex store', () => {
setup();
expect(vm.$store.state.tableFields).toEqual(['account']);
expect(vm.$store.state[MEMBER_TYPES.user].tableFields).toEqual(['account']);
});
it('sets `tableAttrs` in Vuex store', () => {
setup();
expect(vm.$store.state.tableAttrs).toEqual({ table: { 'data-qa-selector': 'members_list' } });
expect(vm.$store.state[MEMBER_TYPES.user].tableAttrs).toEqual({
table: { 'data-qa-selector': 'members_list' },
});
});
it('sets `tableSortableFields` in Vuex store', () => {
setup();
expect(vm.$store.state.tableSortableFields).toEqual(['account']);
expect(vm.$store.state[MEMBER_TYPES.user].tableSortableFields).toEqual(['account']);
});
it('sets `requestFormatter` in Vuex store', () => {
setup();
expect(vm.$store.state.requestFormatter()).toEqual({});
expect(vm.$store.state[MEMBER_TYPES.user].requestFormatter()).toEqual({});
});
it('sets `filteredSearchBar` in Vuex store', () => {
setup();
expect(vm.$store.state.filteredSearchBar).toEqual({ show: false });
expect(vm.$store.state[MEMBER_TYPES.user].filteredSearchBar).toEqual({ show: false });
});
it('sets `memberPath` in Vuex store', () => {
setup();
expect(vm.$store.state.memberPath).toBe('/groups/foo-bar/-/group_members/:id');
expect(vm.$store.state[MEMBER_TYPES.user].memberPath).toBe(
'/groups/foo-bar/-/group_members/:id',
);
});
});
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