Commit 6f6609aa authored by Phil Hughes's avatar Phil Hughes

Merge branch '335964-refactor-approval-settings-app' into 'master'

Update approvals store to be reusable

See merge request gitlab-org/gitlab!66839
parents e741af67 8789bf1d
...@@ -95,3 +95,20 @@ export const mapMRApprovalSettingsResponse = (res) => { ...@@ -95,3 +95,20 @@ export const mapMRApprovalSettingsResponse = (res) => {
minFallbackApprovalsRequired: 0, minFallbackApprovalsRequired: 0,
}; };
}; };
export const groupApprovalsMappers = {
mapDataToState: (data) => ({
preventAuthorApproval: !data.allow_author_approval,
preventMrApprovalRuleEdit: !data.allow_overrides_to_approver_list_per_merge_request,
requireUserPassword: data.require_password_to_approve,
removeApprovalsOnPush: !data.retain_approvals_on_push,
preventCommittersApproval: !data.allow_committer_approval,
}),
mapStateToPayload: (state) => ({
allow_author_approval: !state.settings.preventAuthorApproval,
allow_overrides_to_approver_list_per_merge_request: !state.settings.preventMrApprovalRuleEdit,
require_password_to_approve: state.settings.requireUserPassword,
retain_approvals_on_push: !state.settings.removeApprovalsOnPush,
allow_committer_approval: !state.settings.preventCommittersApproval,
}),
};
import Vue from 'vue'; import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import GroupSettingsApp from './components/group_settings/app.vue'; import GroupSettingsApp from './components/group_settings/app.vue';
import { groupApprovalsMappers } from './mappers';
import createStore from './stores'; import createStore from './stores';
import groupSettingsModule from './stores/modules/group_settings'; import approvalSettingsModule from './stores/modules/approval_settings';
const mountGroupApprovalSettings = (el) => { const mountGroupApprovalSettings = (el) => {
if (!el) { if (!el) {
...@@ -10,7 +11,7 @@ const mountGroupApprovalSettings = (el) => { ...@@ -10,7 +11,7 @@ const mountGroupApprovalSettings = (el) => {
} }
const { defaultExpanded, approvalSettingsPath } = el.dataset; const { defaultExpanded, approvalSettingsPath } = el.dataset;
const store = createStore(groupSettingsModule()); const store = createStore(approvalSettingsModule(groupApprovalsMappers));
return new Vue({ return new Vue({
el, el,
......
import * as Sentry from '@sentry/browser';
import axios from '~/lib/utils/axios_utils';
import * as types from './mutation_types';
export default (mapStateToPayload) => ({
fetchSettings({ commit }, endpoint) {
commit(types.REQUEST_SETTINGS);
return axios
.get(endpoint)
.then(({ data }) => {
commit(types.RECEIVE_SETTINGS_SUCCESS, data);
})
.catch((e) => {
const error = e?.response?.data?.message || e;
Sentry.captureException(error);
commit(types.RECEIVE_SETTINGS_ERROR);
});
},
updateSettings({ commit, state }, endpoint) {
commit(types.REQUEST_UPDATE_SETTINGS);
return axios
.put(endpoint, { ...mapStateToPayload(state) })
.then(({ data }) => {
commit(types.UPDATE_SETTINGS_SUCCESS, data);
})
.catch((e) => {
const error = e?.response?.data?.message || e;
Sentry.captureException(error);
commit(types.UPDATE_SETTINGS_ERROR);
});
},
dismissSuccessMessage({ commit }) {
commit(types.DISMISS_SUCCESS_MESSAGE);
},
dismissErrorMessage({ commit }) {
commit(types.DISMISS_ERROR_MESSAGE);
},
setPreventAuthorApproval({ commit }, { preventAuthorApproval }) {
commit(types.SET_PREVENT_AUTHOR_APPROVAL, preventAuthorApproval);
},
setPreventCommittersApproval({ commit }, { preventCommittersApproval }) {
commit(types.SET_PREVENT_COMMITTERS_APPROVAL, preventCommittersApproval);
},
setPreventMrApprovalRuleEdit({ commit }, { preventMrApprovalRuleEdit }) {
commit(types.SET_PREVENT_MR_APPROVAL_RULE_EDIT, preventMrApprovalRuleEdit);
},
setRemoveApprovalsOnPush({ commit }, { removeApprovalsOnPush }) {
commit(types.SET_REMOVE_APPROVALS_ON_PUSH, removeApprovalsOnPush);
},
setRequireUserPassword({ commit }, { requireUserPassword }) {
commit(types.SET_REQUIRE_USER_PASSWORD, requireUserPassword);
},
});
import actionsFactory from './actions';
import mutationsFactory from './mutations';
import createState from './state';
export default ({ mapStateToPayload, mapDataToState }) => ({
state: createState(),
actions: actionsFactory(mapStateToPayload),
mutations: mutationsFactory(mapDataToState),
});
import { APPROVAL_SETTINGS_I18N } from '../../../constants'; import { APPROVAL_SETTINGS_I18N } from '../../../constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
const mapDataToState = (data) => ({ export default (mapDataToState) => ({
preventAuthorApproval: !data.allow_author_approval,
preventMrApprovalRuleEdit: !data.allow_overrides_to_approver_list_per_merge_request,
requireUserPassword: data.require_password_to_approve,
removeApprovalsOnPush: !data.retain_approvals_on_push,
preventCommittersApproval: !data.allow_committer_approval,
});
export default {
[types.REQUEST_SETTINGS](state) { [types.REQUEST_SETTINGS](state) {
state.isLoading = true; state.isLoading = true;
state.errorMessage = ''; state.errorMessage = '';
...@@ -57,4 +49,4 @@ export default { ...@@ -57,4 +49,4 @@ export default {
[types.SET_REQUIRE_USER_PASSWORD](state, requireUserPassword) { [types.SET_REQUIRE_USER_PASSWORD](state, requireUserPassword) {
state.settings.requireUserPassword = requireUserPassword; state.settings.requireUserPassword = requireUserPassword;
}, },
}; });
import * as Sentry from '@sentry/browser';
import axios from '~/lib/utils/axios_utils';
import * as types from './mutation_types';
const mapStateToPayload = (state) => ({
allow_author_approval: !state.settings.preventAuthorApproval,
allow_overrides_to_approver_list_per_merge_request: !state.settings.preventMrApprovalRuleEdit,
require_password_to_approve: state.settings.requireUserPassword,
retain_approvals_on_push: !state.settings.removeApprovalsOnPush,
allow_committer_approval: !state.settings.preventCommittersApproval,
});
export const fetchSettings = ({ commit }, endpoint) => {
commit(types.REQUEST_SETTINGS);
return axios
.get(endpoint)
.then(({ data }) => {
commit(types.RECEIVE_SETTINGS_SUCCESS, data);
})
.catch((e) => {
const error = e?.response?.data?.message || e;
Sentry.captureException(error);
commit(types.RECEIVE_SETTINGS_ERROR);
});
};
export const updateSettings = ({ commit, state }, endpoint) => {
commit(types.REQUEST_UPDATE_SETTINGS);
return axios
.put(endpoint, { ...mapStateToPayload(state) })
.then(({ data }) => {
commit(types.UPDATE_SETTINGS_SUCCESS, data);
})
.catch((e) => {
const error = e?.response?.data?.message || e;
Sentry.captureException(error);
commit(types.UPDATE_SETTINGS_ERROR);
});
};
export const dismissSuccessMessage = ({ commit }) => {
commit(types.DISMISS_SUCCESS_MESSAGE);
};
export const dismissErrorMessage = ({ commit }) => {
commit(types.DISMISS_ERROR_MESSAGE);
};
export const setPreventAuthorApproval = ({ commit }, { preventAuthorApproval }) => {
commit(types.SET_PREVENT_AUTHOR_APPROVAL, preventAuthorApproval);
};
export const setPreventCommittersApproval = ({ commit }, { preventCommittersApproval }) => {
commit(types.SET_PREVENT_COMMITTERS_APPROVAL, preventCommittersApproval);
};
export const setPreventMrApprovalRuleEdit = ({ commit }, { preventMrApprovalRuleEdit }) => {
commit(types.SET_PREVENT_MR_APPROVAL_RULE_EDIT, preventMrApprovalRuleEdit);
};
export const setRemoveApprovalsOnPush = ({ commit }, { removeApprovalsOnPush }) => {
commit(types.SET_REMOVE_APPROVALS_ON_PUSH, removeApprovalsOnPush);
};
export const setRequireUserPassword = ({ commit }, { requireUserPassword }) => {
commit(types.SET_REQUIRE_USER_PASSWORD, requireUserPassword);
};
import * as actions from './actions';
import mutations from './mutations';
import createState from './state';
export default () => ({
state: createState(),
actions,
mutations,
});
...@@ -4,8 +4,9 @@ import Vuex from 'vuex'; ...@@ -4,8 +4,9 @@ import Vuex from 'vuex';
import ApprovalSettings from 'ee/approvals/components/approval_settings.vue'; import ApprovalSettings from 'ee/approvals/components/approval_settings.vue';
import { APPROVAL_SETTINGS_I18N } from 'ee/approvals/constants'; import { APPROVAL_SETTINGS_I18N } from 'ee/approvals/constants';
import { groupApprovalsMappers } from 'ee/approvals/mappers';
import createStore from 'ee/approvals/stores'; import createStore from 'ee/approvals/stores';
import groupSettingsModule from 'ee/approvals/stores/modules/group_settings'; import approvalSettingsModule from 'ee/approvals/stores/modules/approval_settings/';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
...@@ -20,7 +21,7 @@ describe('ApprovalSettings', () => { ...@@ -20,7 +21,7 @@ describe('ApprovalSettings', () => {
const approvalSettingsPath = 'groups/22/merge_request_approval_settings'; const approvalSettingsPath = 'groups/22/merge_request_approval_settings';
const setupStore = (data = {}) => { const setupStore = (data = {}) => {
const module = groupSettingsModule(); const module = approvalSettingsModule(groupApprovalsMappers);
module.state.settings = data; module.state.settings = data;
actions = module.actions; actions = module.actions;
......
...@@ -6,8 +6,9 @@ import Vuex from 'vuex'; ...@@ -6,8 +6,9 @@ import Vuex from 'vuex';
import ApprovalSettings from 'ee/approvals/components/approval_settings.vue'; import ApprovalSettings from 'ee/approvals/components/approval_settings.vue';
import GroupSettingsApp from 'ee/approvals/components/group_settings/app.vue'; import GroupSettingsApp from 'ee/approvals/components/group_settings/app.vue';
import { groupApprovalsMappers } from 'ee/approvals/mappers';
import { createStoreOptions } from 'ee/approvals/stores'; import { createStoreOptions } from 'ee/approvals/stores';
import groupSettingsModule from 'ee/approvals/stores/modules/group_settings'; import approvalSettingsModule from 'ee/approvals/stores/modules/approval_settings';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -42,7 +43,7 @@ describe('EE Approvals Group Settings App', () => { ...@@ -42,7 +43,7 @@ describe('EE Approvals Group Settings App', () => {
axiosMock = new MockAdapter(axios); axiosMock = new MockAdapter(axios);
axiosMock.onGet('*'); axiosMock.onGet('*');
store = createStoreOptions(groupSettingsModule()); store = createStoreOptions(approvalSettingsModule(groupApprovalsMappers));
}); });
afterEach(() => { afterEach(() => {
......
import { groupApprovalsMappers } from 'ee/approvals/mappers';
describe('approvals mappers', () => {
describe('groupApprovalsMappers', () => {
const groupPayload = {
allow_author_approval: true,
allow_overrides_to_approver_list_per_merge_request: true,
require_password_to_approve: true,
retain_approvals_on_push: true,
allow_committer_approval: true,
};
const groupState = {
settings: {
preventAuthorApproval: false,
preventMrApprovalRuleEdit: false,
requireUserPassword: true,
removeApprovalsOnPush: false,
preventCommittersApproval: false,
},
};
it('maps data to state', () => {
expect(groupApprovalsMappers.mapDataToState(groupPayload)).toStrictEqual(groupState.settings);
});
it('maps state to payload', () => {
expect(groupApprovalsMappers.mapStateToPayload(groupState)).toStrictEqual(groupPayload);
});
});
});
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import * as actions from 'ee/approvals/stores/modules/group_settings/actions'; import actionsFactory from 'ee/approvals/stores/modules/approval_settings/actions';
import * as types from 'ee/approvals/stores/modules/group_settings/mutation_types'; import * as types from 'ee/approvals/stores/modules/approval_settings/mutation_types';
import getInitialState from 'ee/approvals/stores/modules/group_settings/state'; import getInitialState from 'ee/approvals/stores/modules/approval_settings/state';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
...@@ -11,6 +11,7 @@ describe('EE approvals group settings module actions', () => { ...@@ -11,6 +11,7 @@ describe('EE approvals group settings module actions', () => {
let state; let state;
let mock; let mock;
const actions = actionsFactory((data) => data);
const approvalSettingsPath = 'groups/22/merge_request_approval_setting'; const approvalSettingsPath = 'groups/22/merge_request_approval_setting';
beforeEach(() => { beforeEach(() => {
...@@ -63,13 +64,7 @@ describe('EE approvals group settings module actions', () => { ...@@ -63,13 +64,7 @@ describe('EE approvals group settings module actions', () => {
describe('updateSettings', () => { describe('updateSettings', () => {
beforeEach(() => { beforeEach(() => {
state = { state = {
settings: { settings: {},
preventAuthorApproval: false,
preventCommittersApproval: false,
preventMrApprovalRuleEdit: false,
requireUserPassword: false,
removeApprovalsOnPush: false,
},
}; };
}); });
......
import { APPROVAL_SETTINGS_I18N } from 'ee/approvals/constants'; import { APPROVAL_SETTINGS_I18N } from 'ee/approvals/constants';
import mutations from 'ee/approvals/stores/modules/group_settings/mutations'; import mutationsFactory from 'ee/approvals/stores/modules/approval_settings/mutations';
import getInitialState from 'ee/approvals/stores/modules/group_settings/state'; import getInitialState from 'ee/approvals/stores/modules/approval_settings/state';
describe('Group settings store mutations', () => { describe('Group settings store mutations', () => {
let state; let state;
const mapperFn = jest.fn((data) => data);
const mutations = mutationsFactory(mapperFn);
const settings = {
preventAuthorApproval: true,
preventMrApprovalRuleEdit: true,
requireUserPassword: true,
removeApprovalsOnPush: true,
};
beforeEach(() => { beforeEach(() => {
state = getInitialState(); state = getInitialState();
}); });
...@@ -20,19 +29,10 @@ describe('Group settings store mutations', () => { ...@@ -20,19 +29,10 @@ describe('Group settings store mutations', () => {
describe('RECEIVE_SETTINGS_SUCCESS', () => { describe('RECEIVE_SETTINGS_SUCCESS', () => {
it('updates settings', () => { it('updates settings', () => {
mutations.RECEIVE_SETTINGS_SUCCESS(state, { mutations.RECEIVE_SETTINGS_SUCCESS(state, settings);
allow_author_approval: true,
allow_committer_approval: true, expect(mapperFn).toHaveBeenCalledWith(settings);
allow_overrides_to_approver_list_per_merge_request: true, expect(state.settings).toStrictEqual(settings);
require_password_to_approve: true,
retain_approvals_on_push: true,
});
expect(state.settings.preventAuthorApproval).toBe(false);
expect(state.settings.preventCommittersApproval).toBe(false);
expect(state.settings.preventMrApprovalRuleEdit).toBe(false);
expect(state.settings.requireUserPassword).toBe(true);
expect(state.settings.removeApprovalsOnPush).toBe(false);
expect(state.isLoading).toBe(false); expect(state.isLoading).toBe(false);
}); });
}); });
...@@ -58,17 +58,10 @@ describe('Group settings store mutations', () => { ...@@ -58,17 +58,10 @@ describe('Group settings store mutations', () => {
describe('UPDATE_SETTINGS_SUCCESS', () => { describe('UPDATE_SETTINGS_SUCCESS', () => {
it('updates settings', () => { it('updates settings', () => {
mutations.UPDATE_SETTINGS_SUCCESS(state, { mutations.UPDATE_SETTINGS_SUCCESS(state, settings);
allow_author_approval: true,
allow_overrides_to_approver_list_per_merge_request: true,
require_password_to_approve: true,
retain_approvals_on_push: true,
});
expect(state.settings.preventAuthorApproval).toBe(false); expect(mapperFn).toHaveBeenCalledWith(settings);
expect(state.settings.preventMrApprovalRuleEdit).toBe(false); expect(state.settings).toStrictEqual(settings);
expect(state.settings.requireUserPassword).toBe(true);
expect(state.settings.removeApprovalsOnPush).toBe(false);
expect(state.isLoading).toBe(false); expect(state.isLoading).toBe(false);
expect(state.isUpdated).toBe(true); expect(state.isUpdated).toBe(true);
}); });
......
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