Commit 30b6b897 authored by Tim Zallmann's avatar Tim Zallmann Committed by Phil Hughes

Resolve "Multi-file editor commit panel empty state"

parent a9efdb8f
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
'currentBranchId', 'currentBranchId',
'rightPanelCollapsed', 'rightPanelCollapsed',
]), ]),
isCommitInfoShown() {
return this.rightPanelCollapsed || this.fileList.length;
},
}, },
methods: { methods: {
toggleCollapsed() { toggleCollapsed() {
...@@ -36,7 +39,11 @@ ...@@ -36,7 +39,11 @@
</script> </script>
<template> <template>
<div class="multi-file-commit-list"> <div
:class="{
'multi-file-commit-list': isCommitInfoShown
}"
>
<list-collapsed <list-collapsed
v-if="rightPanelCollapsed" v-if="rightPanelCollapsed"
/> />
...@@ -54,12 +61,6 @@ ...@@ -54,12 +61,6 @@
/> />
</li> </li>
</ul> </ul>
<div
v-else
class="help-block prepend-top-0"
>
No changes
</div>
</template> </template>
</div> </div>
</template> </template>
...@@ -23,6 +23,14 @@ ...@@ -23,6 +23,14 @@
type: String, type: String,
required: true, required: true,
}, },
noChangesStateSvgPath: {
type: String,
required: true,
},
committedStateSvgPath: {
type: String,
required: true,
},
}, },
computed: { computed: {
...mapState([ ...mapState([
...@@ -94,6 +102,9 @@ ...@@ -94,6 +102,9 @@
</div> </div>
</template> </template>
</div> </div>
<ide-contextbar/> <ide-contextbar
:no-changes-state-svg-path="noChangesStateSvgPath"
:committed-state-svg-path="committedStateSvgPath"
/>
</div> </div>
</template> </template>
...@@ -10,6 +10,16 @@ ...@@ -10,6 +10,16 @@
icon, icon,
panelResizer, panelResizer,
}, },
props: {
noChangesStateSvgPath: {
type: String,
required: true,
},
committedStateSvgPath: {
type: String,
required: true,
},
},
data() { data() {
return { return {
width: 290, width: 290,
...@@ -46,6 +56,11 @@ ...@@ -46,6 +56,11 @@
collapsed: !this.rightPanelCollapsed, collapsed: !this.rightPanelCollapsed,
}); });
}, },
toggleFullbarCollapsed() {
if (this.rightPanelCollapsed) {
this.toggleCollapsed();
}
},
resizingStarted() { resizingStarted() {
this.setResizingStatus(true); this.setResizingStatus(true);
}, },
...@@ -63,8 +78,11 @@ ...@@ -63,8 +78,11 @@
'is-collapsed': rightPanelCollapsed, 'is-collapsed': rightPanelCollapsed,
}" }"
:style="panelStyle" :style="panelStyle"
@click="toggleFullbarCollapsed"
> >
<div class="multi-file-commit-panel-section"> <div
class="multi-file-commit-panel-section"
>
<header <header
class="multi-file-commit-panel-header" class="multi-file-commit-panel-header"
:class="{ :class="{
...@@ -75,16 +93,20 @@ ...@@ -75,16 +93,20 @@
class="multi-file-commit-panel-header-title" class="multi-file-commit-panel-header-title"
v-if="!rightPanelCollapsed" v-if="!rightPanelCollapsed"
> >
<icon <div
name="list-bulleted" v-if="changedFiles.length"
:size="18" >
/> <icon
Staged name="list-bulleted"
:size="18"
/>
Staged
</div>
</div> </div>
<button <button
type="button" type="button"
class="btn btn-transparent multi-file-commit-panel-collapse-btn" class="btn btn-transparent multi-file-commit-panel-collapse-btn"
@click="toggleCollapsed" @click.stop="toggleCollapsed"
> >
<icon <icon
:name="currentIcon" :name="currentIcon"
...@@ -92,7 +114,10 @@ ...@@ -92,7 +114,10 @@
/> />
</button> </button>
</header> </header>
<repo-commit-section /> <repo-commit-section
:no-changes-state-svg-path="noChangesStateSvgPath"
:committed-state-svg-path="committedStateSvgPath"
/>
</div> </div>
<panel-resizer <panel-resizer
:size.sync="width" :size.sync="width"
......
...@@ -14,6 +14,16 @@ export default { ...@@ -14,6 +14,16 @@ export default {
directives: { directives: {
tooltip, tooltip,
}, },
props: {
noChangesStateSvgPath: {
type: String,
required: true,
},
committedStateSvgPath: {
type: String,
required: true,
},
},
data() { data() {
return { return {
showNewBranchModal: false, showNewBranchModal: false,
...@@ -27,6 +37,7 @@ export default { ...@@ -27,6 +37,7 @@ export default {
'currentProjectId', 'currentProjectId',
'currentBranchId', 'currentBranchId',
'rightPanelCollapsed', 'rightPanelCollapsed',
'lastCommitMsg',
]), ]),
...mapGetters([ ...mapGetters([
'changedFiles', 'changedFiles',
...@@ -37,6 +48,9 @@ export default { ...@@ -37,6 +48,9 @@ export default {
commitMessageCount() { commitMessageCount() {
return this.commitMessage.length; return this.commitMessage.length;
}, },
statusSvg() {
return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath;
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -101,7 +115,12 @@ export default { ...@@ -101,7 +115,12 @@ export default {
</script> </script>
<template> <template>
<div class="multi-file-commit-panel-section"> <div
class="multi-file-commit-panel-section"
:class="{
'multi-file-commit-empty-state-container': !changedFiles.length
}"
>
<modal <modal
v-if="showNewBranchModal" v-if="showNewBranchModal"
:primary-button-label="__('Create new branch')" :primary-button-label="__('Create new branch')"
...@@ -118,54 +137,92 @@ you started editing. Would you like to create a new branch?`)" ...@@ -118,54 +137,92 @@ you started editing. Would you like to create a new branch?`)"
:collapsed="rightPanelCollapsed" :collapsed="rightPanelCollapsed"
@toggleCollapsed="toggleCollapsed" @toggleCollapsed="toggleCollapsed"
/> />
<form <template
class="form-horizontal multi-file-commit-form" v-if="changedFiles.length"
@submit.prevent="tryCommit"
v-if="!rightPanelCollapsed"
> >
<div class="multi-file-commit-fieldset"> <form
<textarea class="form-horizontal multi-file-commit-form"
class="form-control multi-file-commit-message" @submit.prevent="tryCommit"
name="commit-message" v-if="!rightPanelCollapsed"
v-model="commitMessage" >
placeholder="Commit message" <div class="multi-file-commit-fieldset">
> <textarea
</textarea> class="form-control multi-file-commit-message"
name="commit-message"
v-model="commitMessage"
placeholder="Commit message"
>
</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"
:disabled="commitButtonDisabled"
class="btn btn-default btn-sm append-right-10 prepend-left-10"
:class="{ disabled: submitCommitsLoading }"
>
<i
v-if="submitCommitsLoading"
class="js-commit-loading-icon fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="loading"
>
</i>
{{ __('Commit') }}
</button>
<div
class="multi-file-commit-message-count"
>
{{ commitMessageCount }}
</div>
</div>
</form>
</template>
<div
v-else-if="!rightPanelCollapsed"
class="row js-empty-state"
>
<div class="col-xs-10 col-xs-offset-1">
<div class="svg-content svg-80">
<img :src="statusSvg" />
</div>
</div> </div>
<div class="multi-file-commit-fieldset"> <div class="col-xs-10 col-xs-offset-1">
<label <div
v-tooltip class="text-content text-center"
title="Create a new merge request with these changes" v-if="!lastCommitMsg"
data-container="body"
data-placement="top"
>
<input
type="checkbox"
v-model="startNewMR"
/>
Merge Request
</label>
<button
type="submit"
:disabled="commitButtonDisabled"
class="btn btn-default btn-sm append-right-10 prepend-left-10"
:class="{ disabled: submitCommitsLoading }"
> >
<i <h4>
v-if="submitCommitsLoading" {{ __('No changes') }}
class="js-commit-loading-icon fa fa-spinner fa-spin" </h4>
aria-hidden="true" <p>
aria-label="loading" {{ __('Edit files in the editor and commit changes here') }}
> </p>
</i> </div>
Commit
</button>
<div <div
class="multi-file-commit-message-count" class="text-content text-center"
v-else
> >
{{ commitMessageCount }} <h4>
{{ __('All changes are committed') }}
</h4>
<p>
{{ lastCommitMsg }}
</p>
</div> </div>
</div> </div>
</form> </div>
</div> </div>
</template> </template>
...@@ -18,6 +18,8 @@ function initIde(el) { ...@@ -18,6 +18,8 @@ function initIde(el) {
return createElement('ide', { return createElement('ide', {
props: { props: {
emptyStateSvgPath: el.dataset.emptyStateSvgPath, emptyStateSvgPath: el.dataset.emptyStateSvgPath,
noChangesStateSvgPath: el.dataset.noChangesStateSvgPath,
committedStateSvgPath: el.dataset.committedStateSvgPath,
}, },
}); });
}, },
......
...@@ -110,15 +110,7 @@ export const commitChanges = ( ...@@ -110,15 +110,7 @@ export const commitChanges = (
if (data.stats) { if (data.stats) {
commitMsg += ` with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`; commitMsg += ` with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`;
} }
commit(types.SET_LAST_COMMIT_MSG, commitMsg);
flash(
commitMsg,
'notice',
document,
null,
false,
true);
window.dispatchEvent(new Event('resize'));
if (newMr) { if (newMr) {
dispatch('discardAllChanges'); dispatch('discardAllChanges');
......
...@@ -3,6 +3,7 @@ export const TOGGLE_LOADING = 'TOGGLE_LOADING'; ...@@ -3,6 +3,7 @@ export const TOGGLE_LOADING = 'TOGGLE_LOADING';
export const SET_PARENT_TREE_URL = 'SET_PARENT_TREE_URL'; export const SET_PARENT_TREE_URL = 'SET_PARENT_TREE_URL';
export const SET_ROOT = 'SET_ROOT'; export const SET_ROOT = 'SET_ROOT';
export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA'; export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA';
export const SET_LAST_COMMIT_MSG = 'SET_LAST_COMMIT_MSG';
export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED'; export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED';
export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED'; export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED';
export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS'; export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS';
......
...@@ -63,6 +63,11 @@ export default { ...@@ -63,6 +63,11 @@ export default {
updatedAt: lastCommit.commit.authored_date, updatedAt: lastCommit.commit.authored_date,
}); });
}, },
[types.SET_LAST_COMMIT_MSG](state, lastCommitMsg) {
Object.assign(state, {
lastCommitMsg,
});
},
...projectMutations, ...projectMutations,
...fileMutations, ...fileMutations,
...treeMutations, ...treeMutations,
......
...@@ -8,6 +8,7 @@ export default () => ({ ...@@ -8,6 +8,7 @@ export default () => ({
endpoints: {}, endpoints: {},
isRoot: false, isRoot: false,
isInitialRoot: false, isInitialRoot: false,
lastCommitMsg: '',
lastCommitPath: '', lastCommitPath: '',
loading: false, loading: false,
onTopOfBranch: false, onTopOfBranch: false,
...@@ -18,6 +19,6 @@ export default () => ({ ...@@ -18,6 +19,6 @@ export default () => ({
trees: {}, trees: {},
projects: {}, projects: {},
leftPanelCollapsed: false, leftPanelCollapsed: false,
rightPanelCollapsed: true, rightPanelCollapsed: false,
panelResizing: false, panelResizing: false,
}); });
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
width: 100%; width: 100%;
} }
$image-widths: 250 306 394 430; $image-widths: 80 250 306 394 430;
@each $width in $image-widths { @each $width in $image-widths {
&.svg-#{$width} { &.svg-#{$width} {
img, img,
......
...@@ -355,6 +355,11 @@ table.table tr td.multi-file-table-name { ...@@ -355,6 +355,11 @@ table.table tr td.multi-file-table-name {
flex: 1; flex: 1;
} }
.multi-file-commit-empty-state-container {
align-items: center;
justify-content: center;
}
.multi-file-commit-panel-header { .multi-file-commit-panel-header {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -381,7 +386,7 @@ table.table tr td.multi-file-table-name { ...@@ -381,7 +386,7 @@ table.table tr td.multi-file-table-name {
.multi-file-commit-panel-header-title { .multi-file-commit-panel-header-title {
display: flex; display: flex;
flex: 1; flex: 1;
padding: $gl-btn-padding; padding: 0 $gl-btn-padding;
svg { svg {
margin-right: $gl-btn-padding; margin-right: $gl-btn-padding;
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
= webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'ide', force_same_domain: true = webpack_bundle_tag 'ide', force_same_domain: true
#ide.ide-loading{ data: {"empty-state-svg-path" => image_path('illustrations/multi_file_editor_empty.svg')} } #ide.ide-loading{ data: {"empty-state-svg-path" => image_path('illustrations/multi_file_editor_empty.svg'),
"no-changes-state-svg-path" => image_path('illustrations/multi-editor_no_changes_empty.svg'),
"committed-state-svg-path" => image_path('illustrations/multi-editor_all_changes_committed_empty.svg') } }
.text-center .text-center
= icon('spinner spin 2x') = icon('spinner spin 2x')
%h2.clgray= _('Loading the GitLab IDE...') %h2.clgray= _('Loading the GitLab IDE...')
...@@ -48,8 +48,6 @@ feature 'Multi-file editor new directory', :js do ...@@ -48,8 +48,6 @@ feature 'Multi-file editor new directory', :js do
wait_for_requests wait_for_requests
find('.multi-file-commit-panel-collapse-btn').click
fill_in('commit-message', with: 'commit message ide') fill_in('commit-message', with: 'commit message ide')
click_button('Commit') click_button('Commit')
......
...@@ -38,8 +38,6 @@ feature 'Multi-file editor new file', :js do ...@@ -38,8 +38,6 @@ feature 'Multi-file editor new file', :js do
wait_for_requests wait_for_requests
find('.multi-file-commit-panel-collapse-btn').click
fill_in('commit-message', with: 'commit message ide') fill_in('commit-message', with: 'commit message ide')
click_button('Commit') click_button('Commit')
......
...@@ -24,12 +24,6 @@ describe('Multi-file editor commit sidebar list', () => { ...@@ -24,12 +24,6 @@ describe('Multi-file editor commit sidebar list', () => {
vm.$destroy(); vm.$destroy();
}); });
describe('empty file list', () => {
it('renders no changes text', () => {
expect(vm.$el.querySelector('.help-block').textContent.trim()).toBe('No changes');
});
});
describe('with a list of files', () => { describe('with a list of files', () => {
beforeEach((done) => { beforeEach((done) => {
const f = file('file name'); const f = file('file name');
......
...@@ -9,7 +9,10 @@ describe('Multi-file editor right context bar', () => { ...@@ -9,7 +9,10 @@ describe('Multi-file editor right context bar', () => {
beforeEach(() => { beforeEach(() => {
const Component = Vue.extend(ideContextBar); const Component = Vue.extend(ideContextBar);
vm = createComponentWithStore(Component, store); vm = createComponentWithStore(Component, store, {
noChangesStateSvgPath: 'svg',
committedStateSvgPath: 'svg',
});
vm.$store.state.rightPanelCollapsed = false; vm.$store.state.rightPanelCollapsed = false;
...@@ -34,6 +37,17 @@ describe('Multi-file editor right context bar', () => { ...@@ -34,6 +37,17 @@ describe('Multi-file editor right context bar', () => {
it('shows correct icon', () => { it('shows correct icon', () => {
expect(vm.currentIcon).toBe('angle-double-left'); expect(vm.currentIcon).toBe('angle-double-left');
}); });
it('clicking sidebar collapses the bar', () => {
spyOn(vm, 'setPanelCollapsedStatus').and.returnValue(Promise.resolve());
vm.$el.querySelector('.multi-file-commit-panel-section').click();
expect(vm.setPanelCollapsedStatus).toHaveBeenCalledWith({
side: 'right',
collapsed: false,
});
});
}); });
it('clicking toggle collapse button collapses the bar', () => { it('clicking toggle collapse button collapses the bar', () => {
...@@ -46,4 +60,15 @@ describe('Multi-file editor right context bar', () => { ...@@ -46,4 +60,15 @@ describe('Multi-file editor right context bar', () => {
collapsed: true, collapsed: true,
}); });
}); });
it('when expanded clicking the main sidebar is not collapsing the bar', () => {
spyOn(vm, 'setPanelCollapsedStatus').and.returnValue(Promise.resolve());
vm.$el.querySelector('.multi-file-commit-panel-section').click();
expect(vm.setPanelCollapsedStatus).not.toHaveBeenCalledWith({
side: 'right',
collapsed: false,
});
});
}); });
...@@ -12,6 +12,8 @@ describe('ide component', () => { ...@@ -12,6 +12,8 @@ describe('ide component', () => {
vm = createComponentWithStore(Component, store, { vm = createComponentWithStore(Component, store, {
emptyStateSvgPath: 'svg', emptyStateSvgPath: 'svg',
noChangesStateSvgPath: 'svg',
committedStateSvgPath: 'svg',
}).$mount(); }).$mount();
}); });
......
...@@ -4,21 +4,23 @@ import store from '~/ide/stores'; ...@@ -4,21 +4,23 @@ import store from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import repoCommitSection from '~/ide/components/repo_commit_section.vue'; import repoCommitSection from '~/ide/components/repo_commit_section.vue';
import getSetTimeoutPromise from '../../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from '../../helpers/set_timeout_promise_helper';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
describe('RepoCommitSection', () => { describe('RepoCommitSection', () => {
let vm; let vm;
function createComponent() { function createComponent() {
const RepoCommitSection = Vue.extend(repoCommitSection); const Component = Vue.extend(repoCommitSection);
const comp = new RepoCommitSection({ vm = createComponentWithStore(Component, store, {
store, noChangesStateSvgPath: 'svg',
}).$mount(); committedStateSvgPath: 'commitsvg',
});
comp.$store.state.currentProjectId = 'abcproject'; vm.$store.state.currentProjectId = 'abcproject';
comp.$store.state.currentBranchId = 'master'; vm.$store.state.currentBranchId = 'master';
comp.$store.state.projects.abcproject = { vm.$store.state.projects.abcproject = {
web_url: '', web_url: '',
branches: { branches: {
master: { master: {
...@@ -27,15 +29,15 @@ describe('RepoCommitSection', () => { ...@@ -27,15 +29,15 @@ describe('RepoCommitSection', () => {
}, },
}; };
comp.$store.state.rightPanelCollapsed = false; vm.$store.state.rightPanelCollapsed = false;
comp.$store.state.currentBranch = 'master'; vm.$store.state.currentBranch = 'master';
comp.$store.state.openFiles = [file('file1'), file('file2')]; vm.$store.state.openFiles = [file('file1'), file('file2')];
comp.$store.state.openFiles.forEach(f => Object.assign(f, { vm.$store.state.openFiles.forEach(f => Object.assign(f, {
changed: true, changed: true,
content: 'testing', content: 'testing',
})); }));
return comp.$mount(); return vm.$mount();
} }
beforeEach((done) => { beforeEach((done) => {
...@@ -64,6 +66,23 @@ describe('RepoCommitSection', () => { ...@@ -64,6 +66,23 @@ describe('RepoCommitSection', () => {
resetStore(vm.$store); resetStore(vm.$store);
}); });
describe('empty Stage', () => {
it('renders no changes text', () => {
resetStore(vm.$store);
const Component = Vue.extend(repoCommitSection);
vm = createComponentWithStore(Component, store, {
noChangesStateSvgPath: 'nochangessvg',
committedStateSvgPath: 'svg',
}).$mount();
// Vue.nextTick();
expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('No changes');
expect(vm.$el.querySelector('.js-empty-state img').getAttribute('src')).toBe('nochangessvg');
});
});
it('renders a commit section', () => { it('renders a commit section', () => {
const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')]; const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')];
const submitCommit = vm.$el.querySelector('form .btn'); const submitCommit = vm.$el.querySelector('form .btn');
...@@ -115,6 +134,9 @@ describe('RepoCommitSection', () => { ...@@ -115,6 +134,9 @@ describe('RepoCommitSection', () => {
expect(actions[1].content).toEqual(changedFiles[1].content); expect(actions[1].content).toEqual(changedFiles[1].content);
expect(actions[0].file_path).toEqual(changedFiles[0].path); expect(actions[0].file_path).toEqual(changedFiles[0].path);
expect(actions[1].file_path).toEqual(changedFiles[1].path); expect(actions[1].file_path).toEqual(changedFiles[1].path);
expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('All changes are committed');
expect(vm.$el.querySelector('.js-empty-state img').getAttribute('src')).toBe('commitsvg');
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
...@@ -270,13 +270,10 @@ describe('Multi-file store actions', () => { ...@@ -270,13 +270,10 @@ describe('Multi-file store actions', () => {
}).catch(done.fail); }).catch(done.fail);
}); });
it('shows flash notice', (done) => { it('sets last Commit Msg', (done) => {
store.dispatch('commitChanges', { payload, newMr: false }) store.dispatch('commitChanges', { payload, newMr: false })
.then(() => { .then(() => {
const alert = document.querySelector('.flash-container'); expect(store.state.lastCommitMsg).toBe(
expect(alert.querySelector('.flash-notice')).not.toBeNull();
expect(alert.textContent.trim()).toBe(
'Your changes have been committed. Commit 123 with 1 additions, 2 deletions.', 'Your changes have been committed. Commit 123 with 1 additions, 2 deletions.',
); );
......
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