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>
import { mapState, mapActions } from 'vuex';
import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '../../vue_shared/directives/tooltip';
import icon from '../../vue_shared/components/icon.vue';
import modal from '../../vue_shared/components/modal.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 {
components: {
modal,
icon,
commitFilesList,
Actions,
LoadingButton,
},
directives: {
tooltip,
......@@ -27,9 +31,6 @@ export default {
data() {
return {
showNewBranchModal: false,
submitCommitsLoading: false,
startNewMR: false,
commitMessage: '',
};
},
computed: {
......@@ -40,12 +41,15 @@ export default {
'lastCommitMsg',
'changedFiles',
]),
commitButtonDisabled() {
return this.commitMessage === '' || this.submitCommitsLoading || !this.changedFiles.length;
},
commitMessageCount() {
return this.commitMessage.length;
},
...mapState('commit', [
'commitMessage',
'submitCommitLoading',
]),
...mapGetters('commit', [
'commitButtonDisabled',
'discardDraftButtonDisabled',
'branchName',
]),
statusSvg() {
return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath;
},
......@@ -53,42 +57,19 @@ export default {
methods: {
...mapActions([
'checkCommitStatus',
'commitChanges',
'getTreeData',
'setPanelCollapsedStatus',
]),
makeCommit(newBranch = false) {
const createNewBranch = newBranch || this.startNewMR;
const payload = {
branch: createNewBranch ?
`${this.currentBranchId}-${new Date().getTime().toString()}` :
this.currentBranchId,
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;
});
...mapActions('commit', [
'updateCommitMessage',
'discardDraft',
'commitChanges',
]),
makeCommit() {
this.commitChanges();
},
tryCommit() {
this.submitCommitsLoading = true;
this.submitCommitLoading = true;
this.checkCommitStatus()
.then((branchChanged) => {
......@@ -99,7 +80,7 @@ export default {
}
})
.catch(() => {
this.submitCommitsLoading = false;
this.submitCommitLoading = false;
});
},
toggleCollapsed() {
......@@ -140,51 +121,36 @@ you started editing. Would you like to create a new branch?`)"
>
<form
class="form-horizontal multi-file-commit-form"
@submit.prevent="tryCommit"
@submit.prevent.stop="makeCommit"
v-if="!rightPanelCollapsed"
>
<div class="multi-file-commit-fieldset">
<textarea
class="form-control multi-file-commit-message ref-name"
class="form-control multi-file-commit-message"
name="commit-message"
v-model="commitMessage"
placeholder="Commit message"
:value="commitMessage"
placeholder="Write a commit message..."
@input="updateCommitMessage($event.target.value)"
>
</textarea>
</div>
<div class="multi-file-commit-fieldset">
<label
v-tooltip
title="Create a new merge request with these changes"
data-container="body"
data-placement="top"
>
<input
type="checkbox"
v-model="startNewMR"
/>
{{ __('Merge Request') }}
</label>
<button
type="submit"
<div class="clearfix prepend-top-15">
<actions />
<loading-button
:loading="submitCommitLoading"
:disabled="commitButtonDisabled"
class="btn btn-default btn-sm append-right-10 prepend-left-10"
:class="{ disabled: submitCommitsLoading }"
container-class="btn btn-success btn-sm pull-left"
:label="__('Commit')"
@click="makeCommit"
/>
<button
type="button"
class="btn btn-default btn-sm pull-right"
:disabled="discardDraftButtonDisabled"
@click="discardDraft"
>
<i
v-if="submitCommitsLoading"
class="js-commit-loading-icon fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="loading"
>
</i>
{{ __('Commit') }}
Discard draft
</button>
<div
class="multi-file-commit-message-count"
>
{{ commitMessageCount }}
</div>
</div>
</form>
</template>
......
......@@ -3,7 +3,6 @@ import { visitUrl } from '../../lib/utils/url_utility';
import flash from '../../flash';
import service from '../services';
import * as types from './mutation_types';
import { stripHtml } from '../../lib/utils/text_utility';
export const redirectToUrl = (_, url) => visitUrl(url);
......@@ -67,68 +66,6 @@ export const checkCommitStatus = ({ state }) =>
})
.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 = (
{ state, dispatch },
{ projectId, branchId, parent, name, type, content = '', base64 = false },
......
......@@ -4,6 +4,7 @@ import state from './state';
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import commitModule from './modules/commit';
Vue.use(Vuex);
......@@ -12,4 +13,7 @@ export default new Vuex.Store({
actions,
mutations,
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 @@
.ide-view {
display: flex;
height: calc(100vh - #{$header-height});
margin-top: 40px;
color: $almost-black;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
......@@ -467,16 +468,6 @@ table.table tr td.multi-file-table-name {
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 {
height: 80px;
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