Commit 91e1f3c9 authored by Phil Hughes's avatar Phil Hughes

Started adding ability for users to create new branch in IDE

parent fec98d0f
<script>
import { mapActions, mapState, mapGetters } from 'vuex';
import * as consts from '../../stores/modules/commit/constants';
export default {
data() {
return {
COMMIT_TO_CURRENT_BRANCH: consts.COMMIT_TO_CURRENT_BRANCH,
COMMIT_TO_NEW_BRANCH: consts.COMMIT_TO_NEW_BRANCH,
COMMIT_TO_NEW_BRANCH_MR: consts.COMMIT_TO_NEW_BRANCH_MR,
};
},
computed: {
...mapState([
'currentBranchId',
]),
...mapState('commit', [
'commitAction',
]),
...mapGetters('commit', [
'newBranchName',
]),
},
methods: {
...mapActions('commit', [
'updateCommitAction',
'updateBranchName',
]),
},
};
</script>
<template>
<div>
<fieldset>
<label>
<input
type="radio"
name="commit-action"
:value="COMMIT_TO_CURRENT_BRANCH"
@change="updateCommitAction($event.target.value)"
checked
/>
Commit to <strong>{{ currentBranchId }}</strong> branch
</label>
</fieldset>
<fieldset>
<label>
<input
type="radio"
name="commit-action"
:value="COMMIT_TO_NEW_BRANCH"
@change="updateCommitAction($event.target.value)"
/>
Create a new branch
</label>
<template v-if="commitAction === '2'">
<input
type="text"
class="form-control input-sm"
:placeholder="newBranchName"
@input="updateBranchName($event.target.value)"
/>
</template>
</fieldset>
<fieldset>
<label>
<input
type="radio"
name="commit-action"
:value="COMMIT_TO_NEW_BRANCH_MR"
@change="updateCommitAction($event.target.value)"
/>
Create a new branch and merge request
</label>
</fieldset>
</div>
</template>
<script> <script>
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
import icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
import modal from '../../vue_shared/components/modal.vue'; import modal from '../../vue_shared/components/modal.vue';
import commitFilesList from './commit_sidebar/list.vue'; import commitFilesList from './commit_sidebar/list.vue';
import Actions from './commit_sidebar/actions.vue';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
export default { export default {
components: { components: {
modal, modal,
icon, icon,
commitFilesList, commitFilesList,
Actions,
LoadingButton,
}, },
directives: { directives: {
tooltip, tooltip,
...@@ -27,9 +31,6 @@ export default { ...@@ -27,9 +31,6 @@ export default {
data() { data() {
return { return {
showNewBranchModal: false, showNewBranchModal: false,
submitCommitsLoading: false,
startNewMR: false,
commitMessage: '',
}; };
}, },
computed: { computed: {
...@@ -40,12 +41,15 @@ export default { ...@@ -40,12 +41,15 @@ export default {
'lastCommitMsg', 'lastCommitMsg',
'changedFiles', 'changedFiles',
]), ]),
commitButtonDisabled() { ...mapState('commit', [
return this.commitMessage === '' || this.submitCommitsLoading || !this.changedFiles.length; 'commitMessage',
}, 'submitCommitLoading',
commitMessageCount() { ]),
return this.commitMessage.length; ...mapGetters('commit', [
}, 'commitButtonDisabled',
'discardDraftButtonDisabled',
'branchName',
]),
statusSvg() { statusSvg() {
return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath; return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath;
}, },
...@@ -53,42 +57,19 @@ export default { ...@@ -53,42 +57,19 @@ export default {
methods: { methods: {
...mapActions([ ...mapActions([
'checkCommitStatus', 'checkCommitStatus',
'commitChanges',
'getTreeData', 'getTreeData',
'setPanelCollapsedStatus', 'setPanelCollapsedStatus',
]), ]),
makeCommit(newBranch = false) { ...mapActions('commit', [
const createNewBranch = newBranch || this.startNewMR; 'updateCommitMessage',
'discardDraft',
const payload = { 'commitChanges',
branch: createNewBranch ? ]),
`${this.currentBranchId}-${new Date().getTime().toString()}` : makeCommit() {
this.currentBranchId, this.commitChanges();
commit_message: this.commitMessage,
actions: this.changedFiles.map(f => ({
action: f.tempFile ? 'create' : 'update',
file_path: f.path,
content: f.content,
encoding: f.base64 ? 'base64' : 'text',
})),
start_branch: createNewBranch ? this.currentBranchId : undefined,
};
this.showNewBranchModal = false;
this.submitCommitsLoading = true;
this.commitChanges({ payload, newMr: this.startNewMR })
.then(() => {
this.submitCommitsLoading = false;
this.commitMessage = '';
this.startNewMR = false;
})
.catch(() => {
this.submitCommitsLoading = false;
});
}, },
tryCommit() { tryCommit() {
this.submitCommitsLoading = true; this.submitCommitLoading = true;
this.checkCommitStatus() this.checkCommitStatus()
.then((branchChanged) => { .then((branchChanged) => {
...@@ -99,7 +80,7 @@ export default { ...@@ -99,7 +80,7 @@ export default {
} }
}) })
.catch(() => { .catch(() => {
this.submitCommitsLoading = false; this.submitCommitLoading = false;
}); });
}, },
toggleCollapsed() { toggleCollapsed() {
...@@ -140,51 +121,36 @@ you started editing. Would you like to create a new branch?`)" ...@@ -140,51 +121,36 @@ you started editing. Would you like to create a new branch?`)"
> >
<form <form
class="form-horizontal multi-file-commit-form" class="form-horizontal multi-file-commit-form"
@submit.prevent="tryCommit" @submit.prevent.stop="makeCommit"
v-if="!rightPanelCollapsed" v-if="!rightPanelCollapsed"
> >
<div class="multi-file-commit-fieldset"> <div class="multi-file-commit-fieldset">
<textarea <textarea
class="form-control multi-file-commit-message ref-name" class="form-control multi-file-commit-message"
name="commit-message" name="commit-message"
v-model="commitMessage" :value="commitMessage"
placeholder="Commit message" placeholder="Write a commit message..."
@input="updateCommitMessage($event.target.value)"
> >
</textarea> </textarea>
</div> </div>
<div class="multi-file-commit-fieldset"> <div class="clearfix prepend-top-15">
<label <actions />
v-tooltip <loading-button
title="Create a new merge request with these changes" :loading="submitCommitLoading"
data-container="body"
data-placement="top"
>
<input
type="checkbox"
v-model="startNewMR"
/>
{{ __('Merge Request') }}
</label>
<button
type="submit"
:disabled="commitButtonDisabled" :disabled="commitButtonDisabled"
class="btn btn-default btn-sm append-right-10 prepend-left-10" container-class="btn btn-success btn-sm pull-left"
:class="{ disabled: submitCommitsLoading }" :label="__('Commit')"
@click="makeCommit"
/>
<button
type="button"
class="btn btn-default btn-sm pull-right"
:disabled="discardDraftButtonDisabled"
@click="discardDraft"
> >
<i Discard draft
v-if="submitCommitsLoading"
class="js-commit-loading-icon fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="loading"
>
</i>
{{ __('Commit') }}
</button> </button>
<div
class="multi-file-commit-message-count"
>
{{ commitMessageCount }}
</div>
</div> </div>
</form> </form>
</template> </template>
......
...@@ -3,7 +3,6 @@ import { visitUrl } from '../../lib/utils/url_utility'; ...@@ -3,7 +3,6 @@ import { visitUrl } from '../../lib/utils/url_utility';
import flash from '../../flash'; import flash from '../../flash';
import service from '../services'; import service from '../services';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { stripHtml } from '../../lib/utils/text_utility';
export const redirectToUrl = (_, url) => visitUrl(url); export const redirectToUrl = (_, url) => visitUrl(url);
...@@ -67,68 +66,6 @@ export const checkCommitStatus = ({ state }) => ...@@ -67,68 +66,6 @@ export const checkCommitStatus = ({ state }) =>
}) })
.catch(() => flash('Error checking branch data. Please try again.', 'alert', document, null, false, true)); .catch(() => flash('Error checking branch data. Please try again.', 'alert', document, null, false, true));
export const commitChanges = (
{ commit, state, dispatch },
{ payload, newMr },
) =>
service
.commit(state.currentProjectId, payload)
.then(({ data }) => {
const { branch } = payload;
if (!data.short_id) {
flash(data.message, 'alert', document, null, false, true);
return;
}
const selectedProject = state.projects[state.currentProjectId];
const lastCommit = {
commit_path: `${selectedProject.web_url}/commit/${data.id}`,
commit: {
message: data.message,
authored_date: data.committed_date,
},
};
let commitMsg = `Your changes have been committed. Commit ${data.short_id}`;
if (data.stats) {
commitMsg += ` with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`;
}
commit(types.SET_LAST_COMMIT_MSG, commitMsg);
if (newMr) {
dispatch('discardAllChanges');
dispatch(
'redirectToUrl',
`${selectedProject.web_url}/merge_requests/new?merge_request%5Bsource_branch%5D=${branch}`,
);
} else {
commit(types.SET_BRANCH_WORKING_REFERENCE, {
projectId: state.currentProjectId,
branchId: state.currentBranchId,
reference: data.id,
});
state.changedFiles.forEach((entry) => {
commit(types.SET_LAST_COMMIT_DATA, {
entry,
lastCommit,
});
});
dispatch('discardAllChanges');
window.scrollTo(0, 0);
}
})
.catch((err) => {
let errMsg = 'Error committing changes. Please try again.';
if (err.response.data && err.response.data.message) {
errMsg += ` (${stripHtml(err.response.data.message)})`;
}
flash(errMsg, 'alert', document, null, false, true);
window.dispatchEvent(new Event('resize'));
});
export const createTempEntry = ( export const createTempEntry = (
{ state, dispatch }, { state, dispatch },
{ projectId, branchId, parent, name, type, content = '', base64 = false }, { projectId, branchId, parent, name, type, content = '', base64 = false },
......
...@@ -4,6 +4,7 @@ import state from './state'; ...@@ -4,6 +4,7 @@ import state from './state';
import * as actions from './actions'; import * as actions from './actions';
import * as getters from './getters'; import * as getters from './getters';
import mutations from './mutations'; import mutations from './mutations';
import commitModule from './modules/commit';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -12,4 +13,7 @@ export default new Vuex.Store({ ...@@ -12,4 +13,7 @@ export default new Vuex.Store({
actions, actions,
mutations, mutations,
getters, getters,
modules: {
commit: commitModule,
},
}); });
import * as types from './mutation_types';
import * as rootTypes from '../../mutation_types';
import service from '../../../services';
import flash from '../../../../flash';
import { stripHtml } from '../../../../lib/utils/text_utility';
export const updateCommitMessage = ({ commit }, message) => {
commit(types.UPDATE_COMMIT_MESSAGE, message);
};
export const discardDraft = ({ commit }) => {
commit(types.UPDATE_COMMIT_MESSAGE, '');
};
export const updateCommitAction = ({ commit }, commitAction) => {
commit(types.UPDATE_COMMIT_ACTION, commitAction);
};
export const updateBranchName = ({ commit }, branchName) => {
commit(types.UPDATE_NEW_BRANCH_NAME, branchName);
};
export const commitChanges = ({ commit, state, getters, dispatch, rootState }) => {
const payload = {
branch: getters.branchName,
commit_message: state.commitMessage,
actions: rootState.changedFiles.map(f => ({
action: f.tempFile ? 'create' : 'update',
file_path: f.path,
content: f.content,
encoding: f.base64 ? 'base64' : 'text',
})),
start_branch: undefined,
};
commit(types.UPDATE_LOADING, true);
console.log(payload);
return;
service
.commit(state.currentProjectId, payload)
.then(({ data }) => {
const { branch } = payload;
if (!data.short_id) {
flash(data.message, 'alert', document, null, false, true);
return;
}
const selectedProject = state.projects[state.currentProjectId];
const lastCommit = {
commit_path: `${selectedProject.web_url}/commit/${data.id}`,
commit: {
message: data.message,
authored_date: data.committed_date,
},
};
let commitMsg = `Your changes have been committed. Commit ${data.short_id}`;
if (data.stats) {
commitMsg += ` with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`;
}
commit(rootTypes.SET_LAST_COMMIT_MSG, commitMsg, { root: true });
if (false) {
dispatch('discardAllChanges', null, { root: true });
dispatch(
'redirectToUrl',
`${selectedProject.web_url}/merge_requests/new?merge_request[source_branch]=${branch}&merge_request[target_branch]=${rottState.currentBranchId}`,
{ root: true },
);
} else {
commit(rootTypes.SET_BRANCH_WORKING_REFERENCE, {
projectId: state.currentProjectId,
branchId: state.currentBranchId,
reference: data.id,
}, { root: true });
state.changedFiles.forEach((entry) => {
commit(rootTypes.SET_LAST_COMMIT_DATA, {
entry,
lastCommit,
}, { root: true });
});
dispatch('discardAllChanges', null, { root: true });
window.scrollTo(0, 0);
}
})
.catch((err) => {
let errMsg = 'Error committing changes. Please try again.';
if (err.response.data && err.response.data.message) {
errMsg += ` (${stripHtml(err.response.data.message)})`;
}
flash(errMsg, 'alert', document, null, false, true);
window.dispatchEvent(new Event('resize'));
});
};
export const COMMIT_TO_CURRENT_BRANCH = '1';
export const COMMIT_TO_NEW_BRANCH = '2';
export const COMMIT_TO_NEW_BRANCH_MR = '3';
import * as consts from './constants';
export const discardDraftButtonDisabled = state => state.commitMessage === '' || state.submitCommitLoading;
export const commitButtonDisabled = (state, getters, rootState) =>
getters.discardDraftButtonDisabled || !rootState.changedFiles.length;
export const newBranchName = (state, getters, rootState) =>
`${gon.current_username}-${rootState.currentBranchId}-patch-${`${new Date().getTime()}`.substr(-5)}`;
export const branchName = (state, getters, rootState) => {
if (
state.commitAction === consts.COMMIT_TO_NEW_BRANCH ||
state.commitAction === consts.COMMIT_TO_NEW_BRANCH_MR
) {
if (state.newBranchName === '') {
return getters.newBranchName;
}
return state.newBranchName;
}
return rootState.currentBranchId;
};
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
import * as getters from './getters';
export default {
namespaced: true,
state: state(),
mutations,
actions,
getters,
};
export const UPDATE_COMMIT_MESSAGE = 'UPDATE_COMMIT_MESSAGE';
export const UPDATE_COMMIT_ACTION = 'UPDATE_COMMIT_ACTION';
export const UPDATE_NEW_BRANCH_NAME = 'UPDATE_NEW_BRANCH_NAME';
export const UPDATE_LOADING = 'UPDATE_LOADING';
import * as types from './mutation_types';
export default {
[types.UPDATE_COMMIT_MESSAGE](state, commitMessage) {
Object.assign(state, {
commitMessage,
});
},
[types.UPDATE_COMMIT_ACTION](state, commitAction) {
Object.assign(state, {
commitAction,
});
},
[types.UPDATE_NEW_BRANCH_NAME](state, newBranchName) {
Object.assign(state, {
newBranchName,
});
},
[types.UPDATE_LOADING](state, submitCommitLoading) {
Object.assign(state, {
submitCommitLoading,
});
},
};
export default () => ({
commitMessage: '',
commitAction: '1',
newBranchName: '',
submitCommitLoading: false,
});
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
.ide-view { .ide-view {
display: flex; display: flex;
height: calc(100vh - #{$header-height}); height: calc(100vh - #{$header-height});
margin-top: 40px;
color: $almost-black; color: $almost-black;
border-top: 1px solid $white-dark; border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark; border-bottom: 1px solid $white-dark;
...@@ -467,16 +468,6 @@ table.table tr td.multi-file-table-name { ...@@ -467,16 +468,6 @@ table.table tr td.multi-file-table-name {
border-top: 1px solid $white-dark; border-top: 1px solid $white-dark;
} }
.multi-file-commit-fieldset {
display: flex;
align-items: center;
padding-bottom: 12px;
.btn {
flex: 1;
}
}
.multi-file-commit-message.form-control { .multi-file-commit-message.form-control {
height: 80px; height: 80px;
resize: none; resize: none;
......
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