Commit 17e5f87c authored by Himanshu Kapoor's avatar Himanshu Kapoor

Use GlModal for Create Branch Modal in the Web IDE

Migrate the create branch modal in Web IDE to use GlModal. The modal
appears when the branch you're trying to commit on is behind its remote
counterpart.
parent 5cddf3a9
<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