Commit 9cd9bd00 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '217729-create-branch-modal' into 'master'

WebIDE: Migrate create branch modal to use GlModal

Closes #217729

See merge request gitlab-org/gitlab!32087
parents fa6a71f0 17e5f87c
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import { n__, __ } from '~/locale'; import { n__, __ } from '~/locale';
import { GlModal } from '@gitlab/ui';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import CommitMessageField from './message_field.vue'; import CommitMessageField from './message_field.vue';
import Actions from './actions.vue'; import Actions from './actions.vue';
import SuccessMessage from './success_message.vue'; import SuccessMessage from './success_message.vue';
import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants';
import consts from '../../stores/modules/commit/constants';
export default { export default {
components: { components: {
...@@ -13,6 +15,7 @@ export default { ...@@ -13,6 +15,7 @@ export default {
LoadingButton, LoadingButton,
CommitMessageField, CommitMessageField,
SuccessMessage, SuccessMessage,
GlModal,
}, },
data() { data() {
return { return {
...@@ -54,7 +57,20 @@ export default { ...@@ -54,7 +57,20 @@ export default {
}, },
methods: { methods: {
...mapActions(['updateActivityBarView']), ...mapActions(['updateActivityBarView']),
...mapActions('commit', ['updateCommitMessage', 'discardDraft', 'commitChanges']), ...mapActions('commit', [
'updateCommitMessage',
'discardDraft',
'commitChanges',
'updateCommitAction',
]),
commit() {
return this.commitChanges().catch(() => {
this.$refs.createBranchModal.show();
});
},
forceCreateNewBranch() {
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit());
},
toggleIsCompact() { toggleIsCompact() {
if (this.currentViewIsCommitView) { if (this.currentViewIsCommitView) {
this.isCompact = !this.isCompact; this.isCompact = !this.isCompact;
...@@ -119,13 +135,13 @@ export default { ...@@ -119,13 +135,13 @@ export default {
</button> </button>
<p class="text-center bold">{{ overviewText }}</p> <p class="text-center bold">{{ overviewText }}</p>
</div> </div>
<form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commitChanges"> <form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commit">
<transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition> <transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition>
<commit-message-field <commit-message-field
:text="commitMessage" :text="commitMessage"
:placeholder="preBuiltCommitMessage" :placeholder="preBuiltCommitMessage"
@input="updateCommitMessage" @input="updateCommitMessage"
@submit="commitChanges" @submit="commit"
/> />
<div class="clearfix prepend-top-15"> <div class="clearfix prepend-top-15">
<actions /> <actions />
...@@ -133,7 +149,7 @@ export default { ...@@ -133,7 +149,7 @@ export default {
:loading="submitCommitLoading" :loading="submitCommitLoading"
:label="commitButtonText" :label="commitButtonText"
container-class="btn btn-success btn-sm float-left qa-commit-button" container-class="btn btn-success btn-sm float-left qa-commit-button"
@click="commitChanges" @click="commit"
/> />
<button <button
v-if="!discardDraftButtonDisabled" v-if="!discardDraftButtonDisabled"
...@@ -152,6 +168,19 @@ export default { ...@@ -152,6 +168,19 @@ export default {
{{ __('Collapse') }} {{ __('Collapse') }}
</button> </button>
</div> </div>
<gl-modal
ref="createBranchModal"
modal-id="ide-create-branch-modal"
:ok-title="__('Create new branch')"
:title="__('Branch has changed')"
ok-variant="success"
@ok="forceCreateNewBranch"
>
{{
__(`This branch has changed since you started editing.
Would you like to create a new branch?`)
}}
</gl-modal>
</form> </form>
</transition> </transition>
</div> </div>
......
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import CommitFilesList from './commit_sidebar/list.vue'; import CommitFilesList from './commit_sidebar/list.vue';
import EmptyState from './commit_sidebar/empty_state.vue'; import EmptyState from './commit_sidebar/empty_state.vue';
import consts from '../stores/modules/commit/constants';
import { leftSidebarViews, stageKeys } from '../constants'; import { leftSidebarViews, stageKeys } from '../constants';
export default { export default {
components: { components: {
DeprecatedModal,
CommitFilesList, CommitFilesList,
EmptyState, EmptyState,
}, },
...@@ -53,10 +50,6 @@ export default { ...@@ -53,10 +50,6 @@ export default {
}, },
methods: { methods: {
...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']), ...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']),
...mapActions('commit', ['commitChanges', 'updateCommitAction']),
forceCreateNewBranch() {
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commitChanges());
},
}, },
stageKeys, stageKeys,
}; };
...@@ -64,20 +57,6 @@ export default { ...@@ -64,20 +57,6 @@ export default {
<template> <template>
<div class="multi-file-commit-panel-section"> <div class="multi-file-commit-panel-section">
<deprecated-modal
id="ide-create-branch-modal"
:primary-button-label="__('Create new branch')"
:title="__('Branch has changed')"
kind="success"
@submit="forceCreateNewBranch"
>
<template slot="body">
{{
__(`This branch has changed since you started editing.
Would you like to create a new branch?`)
}}
</template>
</deprecated-modal>
<template v-if="showStageUnstageArea"> <template v-if="showStageUnstageArea">
<commit-files-list <commit-files-list
:key-prefix="$options.stageKeys.staged" :key-prefix="$options.stageKeys.staged"
......
import $ from 'jquery';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import flash from '~/flash'; import flash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status';
import * as rootTypes from '../../mutation_types'; import * as rootTypes from '../../mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from '../../utils'; import { createCommitPayload, createNewMergeRequestUrl } from '../../utils';
import router from '../../../ide_router'; import router from '../../../ide_router';
...@@ -215,25 +215,23 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ...@@ -215,25 +215,23 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
); );
}) })
.catch(err => { .catch(err => {
if (err.response.status === 400) {
$('#ide-create-branch-modal').modal('show');
} else {
dispatch(
'setErrorMessage',
{
text: __('An error occurred while committing your changes.'),
action: () =>
dispatch('commitChanges').then(() =>
dispatch('setErrorMessage', null, { root: true }),
),
actionText: __('Please try again'),
},
{ root: true },
);
window.dispatchEvent(new Event('resize'));
}
commit(types.UPDATE_LOADING, false); commit(types.UPDATE_LOADING, false);
// don't catch bad request errors, let the view handle them
if (err.response.status === httpStatusCodes.BAD_REQUEST) throw err;
dispatch(
'setErrorMessage',
{
text: __('An error occurred while committing your changes.'),
action: () =>
dispatch('commitChanges').then(() => dispatch('setErrorMessage', null, { root: true })),
actionText: __('Please try again'),
},
{ root: true },
);
window.dispatchEvent(new Event('resize'));
}); });
}; };
......
import Vue from 'vue'; import Vue from 'vue';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { projectData } from 'jest/ide/mock_data'; import { projectData } from 'jest/ide/mock_data';
import store from '~/ide/stores'; import store from '~/ide/stores';
import CommitForm from '~/ide/components/commit_sidebar/form.vue'; import CommitForm from '~/ide/components/commit_sidebar/form.vue';
...@@ -31,10 +30,10 @@ describe('IDE commit form', () => { ...@@ -31,10 +30,10 @@ describe('IDE commit form', () => {
}); });
describe('compact', () => { describe('compact', () => {
beforeEach(done => { beforeEach(() => {
vm.isCompact = true; vm.isCompact = true;
vm.$nextTick(done); return vm.$nextTick();
}); });
it('renders commit button in compact mode', () => { it('renders commit button in compact mode', () => {
...@@ -46,95 +45,84 @@ describe('IDE commit form', () => { ...@@ -46,95 +45,84 @@ describe('IDE commit form', () => {
expect(vm.$el.querySelector('form')).toBeNull(); expect(vm.$el.querySelector('form')).toBeNull();
}); });
it('renders overview text', done => { it('renders overview text', () => {
vm.$store.state.stagedFiles.push('test'); vm.$store.state.stagedFiles.push('test');
vm.$nextTick(() => { return vm.$nextTick(() => {
expect(vm.$el.querySelector('p').textContent).toContain('1 changed file'); expect(vm.$el.querySelector('p').textContent).toContain('1 changed file');
done();
}); });
}); });
it('shows form when clicking commit button', done => { it('shows form when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); vm.$el.querySelector('.btn-primary').click();
vm.$nextTick(() => { return vm.$nextTick(() => {
expect(vm.$el.querySelector('form')).not.toBeNull(); expect(vm.$el.querySelector('form')).not.toBeNull();
done();
}); });
}); });
it('toggles activity bar view when clicking commit button', done => { it('toggles activity bar view when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); vm.$el.querySelector('.btn-primary').click();
vm.$nextTick(() => { return vm.$nextTick(() => {
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name); expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
done();
}); });
}); });
it('collapses if lastCommitMsg is set to empty and current view is not commit view', done => { it('collapses if lastCommitMsg is set to empty and current view is not commit view', () => {
store.state.lastCommitMsg = 'abc'; store.state.lastCommitMsg = 'abc';
store.state.currentActivityView = leftSidebarViews.edit.name; store.state.currentActivityView = leftSidebarViews.edit.name;
vm.$nextTick(() => { return vm
// if commit message is set, form is uncollapsed .$nextTick()
expect(vm.isCompact).toBe(false); .then(() => {
// if commit message is set, form is uncollapsed
expect(vm.isCompact).toBe(false);
store.state.lastCommitMsg = ''; store.state.lastCommitMsg = '';
vm.$nextTick(() => { return vm.$nextTick();
})
.then(() => {
// collapsed when set to empty // collapsed when set to empty
expect(vm.isCompact).toBe(true); expect(vm.isCompact).toBe(true);
done();
}); });
});
}); });
}); });
describe('full', () => { describe('full', () => {
beforeEach(done => { beforeEach(() => {
vm.isCompact = false; vm.isCompact = false;
vm.$nextTick(done); return vm.$nextTick();
}); });
it('updates commitMessage in store on input', done => { it('updates commitMessage in store on input', () => {
const textarea = vm.$el.querySelector('textarea'); const textarea = vm.$el.querySelector('textarea');
textarea.value = 'testing commit message'; textarea.value = 'testing commit message';
textarea.dispatchEvent(new Event('input')); textarea.dispatchEvent(new Event('input'));
waitForPromises() return vm.$nextTick().then(() => {
.then(() => { expect(vm.$store.state.commit.commitMessage).toBe('testing commit message');
expect(vm.$store.state.commit.commitMessage).toBe('testing commit message'); });
})
.then(done)
.catch(done.fail);
}); });
it('updating currentActivityView not to commit view sets compact mode', done => { it('updating currentActivityView not to commit view sets compact mode', () => {
store.state.currentActivityView = 'a'; store.state.currentActivityView = 'a';
vm.$nextTick(() => { return vm.$nextTick(() => {
expect(vm.isCompact).toBe(true); expect(vm.isCompact).toBe(true);
done();
}); });
}); });
it('always opens itself in full view current activity view is not commit view when clicking commit button', done => { it('always opens itself in full view current activity view is not commit view when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); vm.$el.querySelector('.btn-primary').click();
vm.$nextTick(() => { return vm.$nextTick(() => {
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name); expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
expect(vm.isCompact).toBe(false); expect(vm.isCompact).toBe(false);
done();
}); });
}); });
...@@ -143,41 +131,54 @@ describe('IDE commit form', () => { ...@@ -143,41 +131,54 @@ describe('IDE commit form', () => {
expect(vm.$el.querySelector('.btn-default').textContent).toContain('Collapse'); expect(vm.$el.querySelector('.btn-default').textContent).toContain('Collapse');
}); });
it('resets commitMessage when clicking discard button', done => { it('resets commitMessage when clicking discard button', () => {
vm.$store.state.commit.commitMessage = 'testing commit message'; vm.$store.state.commit.commitMessage = 'testing commit message';
waitForPromises() return vm
.$nextTick()
.then(() => { .then(() => {
vm.$el.querySelector('.btn-default').click(); vm.$el.querySelector('.btn-default').click();
}) })
.then(Vue.nextTick) .then(() => vm.$nextTick())
.then(() => { .then(() => {
expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message'); expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message');
}) });
.then(done)
.catch(done.fail);
}); });
}); });
describe('when submitting', () => { describe('when submitting', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(vm, 'commitChanges').mockImplementation(() => {}); jest.spyOn(vm, 'commitChanges');
vm.$store.state.stagedFiles.push('test'); vm.$store.state.stagedFiles.push('test');
vm.$store.state.commit.commitMessage = 'testing commit message';
}); });
it('calls commitChanges', done => { it('calls commitChanges', () => {
vm.$store.state.commit.commitMessage = 'testing commit message'; vm.commitChanges.mockResolvedValue({ success: true });
return vm.$nextTick().then(() => {
vm.$el.querySelector('.btn-success').click();
expect(vm.commitChanges).toHaveBeenCalled();
});
});
it('opens new branch modal if commitChanges throws an error', () => {
vm.commitChanges.mockRejectedValue({ success: false });
waitForPromises() jest.spyOn(vm.$refs.createBranchModal, 'show').mockImplementation();
return vm
.$nextTick()
.then(() => { .then(() => {
vm.$el.querySelector('.btn-success').click(); vm.$el.querySelector('.btn-success').click();
return vm.$nextTick();
}) })
.then(Vue.nextTick)
.then(() => { .then(() => {
expect(vm.commitChanges).toHaveBeenCalled(); expect(vm.$refs.createBranchModal.show).toHaveBeenCalled();
}) });
.then(done)
.catch(done.fail);
}); });
}); });
}); });
......
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